diff --git a/BUILD.gn b/BUILD.gn
index 2d67eaa..b42cb10 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -198,6 +198,7 @@
       "//ui/display:display_unittests",
       "//ui/events:events_unittests",
       "//ui/gl:gl_unittests",
+      "//ui/latency_info:latency_info_unittests",
       "//ui/touch_selection:ui_touch_selection_unittests",
       "//url/ipc:url_ipc_unittests",
     ]
diff --git a/DEPS b/DEPS
index 00ac765..2b0f99a8 100644
--- a/DEPS
+++ b/DEPS
@@ -39,11 +39,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': '58700da76b3823de878dde82fee11b80daf7fe18',
+  'skia_revision': '2892668f1b36de25c63a70858dfab5ff0f5caf72',
   # 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': 'f7a114121d146bca920e8c814067d958e0f839d3',
+  'v8_revision': 'bbba46bf9c9ddfcb7adaa4f79eefd370ebea6502',
   # 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.
diff --git a/android_webview/browser/find_helper.cc b/android_webview/browser/find_helper.cc
index 7eebbf2..8fc9979 100644
--- a/android_webview/browser/find_helper.cc
+++ b/android_webview/browser/find_helper.cc
@@ -39,7 +39,7 @@
 
   async_find_started_ = true;
 
-  StartNewRequest(search_string);
+  StartNewSession(search_string);
 
   if (MaybeHandleEmptySearch(search_string))
     return;
@@ -66,6 +66,8 @@
   if (!async_find_started_)
     return;
 
+  current_request_id_ = find_request_id_counter_++;
+
   if (MaybeHandleEmptySearch(last_search_string_))
     return;
 
@@ -95,7 +97,7 @@
   return true;
 }
 
-void FindHelper::StartNewRequest(const base::string16& search_string) {
+void FindHelper::StartNewSession(const base::string16& search_string) {
   current_request_id_ = find_request_id_counter_++;
   last_search_string_ = search_string;
   last_match_count_ = -1;
diff --git a/android_webview/browser/find_helper.h b/android_webview/browser/find_helper.h
index a2e36e7f..ada9084 100644
--- a/android_webview/browser/find_helper.h
+++ b/android_webview/browser/find_helper.h
@@ -43,7 +43,7 @@
   void ClearMatches();
 
  private:
-  void StartNewRequest(const base::string16& search_string);
+  void StartNewSession(const base::string16& search_string);
   bool MaybeHandleEmptySearch(const base::string16& search_string);
   void NotifyResults(int active_ordinal, int match_count, bool finished);
 
diff --git a/ash/system/toast/OWNER b/ash/system/toast/OWNERS
similarity index 100%
rename from ash/system/toast/OWNER
rename to ash/system/toast/OWNERS
diff --git a/base/cancelable_callback.h b/base/cancelable_callback.h
index 47dfb2d5..0034fdd 100644
--- a/base/cancelable_callback.h
+++ b/base/cancelable_callback.h
@@ -42,6 +42,8 @@
 #ifndef BASE_CANCELABLE_CALLBACK_H_
 #define BASE_CANCELABLE_CALLBACK_H_
 
+#include <utility>
+
 #include "base/base_export.h"
 #include "base/bind.h"
 #include "base/callback.h"
@@ -103,7 +105,7 @@
 
  private:
   void Forward(A... args) const {
-    callback_.Run(args...);
+    callback_.Run(std::forward<A>(args)...);
   }
 
   // Helper method to bind |forwarder_| using a weak pointer from
diff --git a/base/cancelable_callback_unittest.cc b/base/cancelable_callback_unittest.cc
index 6d0a114..ca6283c 100644
--- a/base/cancelable_callback_unittest.cc
+++ b/base/cancelable_callback_unittest.cc
@@ -4,9 +4,12 @@
 
 #include "base/cancelable_callback.h"
 
+#include <memory>
+
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
 #include "base/single_thread_task_runner.h"
@@ -26,6 +29,10 @@
 void IncrementBy(int* count, int n) { (*count) += n; }
 void RefCountedParam(const scoped_refptr<TestRefCounted>& ref_counted) {}
 
+void OnMoveOnlyReceived(int* value, std::unique_ptr<int> result) {
+  *value = *result;
+}
+
 // Cancel().
 //  - Callback can be run multiple times.
 //  - After Cancel(), Run() completes but has no effect.
@@ -182,5 +189,17 @@
   EXPECT_EQ(1, count);
 }
 
+// CancelableCallback can be used with move-only types.
+TEST(CancelableCallbackTest, MoveOnlyType) {
+  const int kExpectedResult = 42;
+
+  int result = 0;
+  CancelableCallback<void(std::unique_ptr<int>)> cb(
+      base::Bind(&OnMoveOnlyReceived, base::Unretained(&result)));
+  cb.callback().Run(base::WrapUnique(new int(kExpectedResult)));
+
+  EXPECT_EQ(kExpectedResult, result);
+}
+
 }  // namespace
 }  // namespace base
diff --git a/base/metrics/statistics_recorder.cc b/base/metrics/statistics_recorder.cc
index 9aafe18..f0bb914 100644
--- a/base/metrics/statistics_recorder.cc
+++ b/base/metrics/statistics_recorder.cc
@@ -37,6 +37,14 @@
     const HistogramMap::iterator& iter, bool include_persistent)
     : iter_(iter),
       include_persistent_(include_persistent) {
+  // The starting location could point to a persistent histogram when such
+  // is not wanted. If so, skip it.
+  if (!include_persistent_ && iter_ != histograms_->end() &&
+      (iter_->second->flags() & HistogramBase::kIsPersistent)) {
+    // This operator will continue to skip until a non-persistent histogram
+    // is found.
+    operator++();
+  }
 }
 
 StatisticsRecorder::HistogramIterator::HistogramIterator(
@@ -287,20 +295,13 @@
 
 // static
 HistogramBase* StatisticsRecorder::FindHistogram(base::StringPiece name) {
-  if (lock_ == NULL)
-    return NULL;
-
-  // Import histograms from known persistent storage. Histograms could have
-  // been added by other processes and they must be fetched and recognized
-  // locally. If the persistent memory segment is not shared between processes,
-  // this call does nothing.
   // This must be called *before* the lock is acquired below because it will
   // call back into this object to register histograms. Those called methods
   // will acquire the lock at that time.
-  GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
-  if (allocator)
-    allocator->ImportHistogramsToStatisticsRecorder();
+  ImportGlobalPersistentHistograms();
 
+  if (lock_ == NULL)
+    return NULL;
   base::AutoLock auto_lock(*lock_);
   if (histograms_ == NULL)
     return NULL;
@@ -314,6 +315,7 @@
 // static
 StatisticsRecorder::HistogramIterator StatisticsRecorder::begin(
     bool include_persistent) {
+  ImportGlobalPersistentHistograms();
   return HistogramIterator(histograms_->begin(), include_persistent);
 }
 
@@ -423,6 +425,20 @@
   g_statistics_recorder_.private_instance_ = 0;
 }
 
+// static
+void StatisticsRecorder::ImportGlobalPersistentHistograms() {
+  if (lock_ == NULL)
+    return;
+
+  // Import histograms from known persistent storage. Histograms could have
+  // been added by other processes and they must be fetched and recognized
+  // locally. If the persistent memory segment is not shared between processes,
+  // this call does nothing.
+  GlobalHistogramAllocator* allocator = GlobalHistogramAllocator::Get();
+  if (allocator)
+    allocator->ImportHistogramsToStatisticsRecorder();
+}
+
 // This singleton instance should be started during the single threaded portion
 // of main(), and hence it is not thread safe.  It initializes globals to
 // provide support for all future calls.
diff --git a/base/metrics/statistics_recorder.h b/base/metrics/statistics_recorder.h
index 2fa03f9..6c436c2 100644
--- a/base/metrics/statistics_recorder.h
+++ b/base/metrics/statistics_recorder.h
@@ -195,6 +195,10 @@
   FRIEND_TEST_ALL_PREFIXES(HistogramDeltaSerializationTest,
                            DeserializeHistogramAndAddSamples);
 
+  // Imports histograms from global persistent memory. The global lock must
+  // not be held during this call.
+  static void ImportGlobalPersistentHistograms();
+
   // The constructor just initializes static members. Usually client code should
   // use Initialize to do this. But in test code, you can friend this class and
   // call the constructor to get a clean StatisticsRecorder.
diff --git a/base/metrics/statistics_recorder_unittest.cc b/base/metrics/statistics_recorder_unittest.cc
index aede0b1..813fbd13 100644
--- a/base/metrics/statistics_recorder_unittest.cc
+++ b/base/metrics/statistics_recorder_unittest.cc
@@ -19,20 +19,29 @@
 
 namespace base {
 
-class StatisticsRecorderTest : public testing::Test {
+class StatisticsRecorderTest : public testing::TestWithParam<bool> {
  protected:
-  void SetUp() override {
+  const int32_t kAllocatorMemorySize = 64 << 10;  // 64 KiB
+
+  StatisticsRecorderTest() : use_persistent_histogram_allocator_(GetParam()) {
     // Get this first so it never gets created in persistent storage and will
     // not appear in the StatisticsRecorder after it is re-initialized.
     PersistentHistogramAllocator::GetCreateHistogramResultHistogram();
+
     // Each test will have a clean state (no Histogram / BucketRanges
     // registered).
     InitializeStatisticsRecorder();
+
+    // Use persistent memory for histograms if so indicated by test parameter.
+    if (use_persistent_histogram_allocator_) {
+      GlobalHistogramAllocator::CreateWithLocalMemory(
+          kAllocatorMemorySize, 0, "StatisticsRecorderTest");
+    }
   }
 
-  void TearDown() override {
-    UninitializeStatisticsRecorder();
+  ~StatisticsRecorderTest() override {
     GlobalHistogramAllocator::ReleaseForTesting();
+    UninitializeStatisticsRecorder();
   }
 
   void InitializeStatisticsRecorder() {
@@ -61,10 +70,27 @@
     delete histogram;
   }
 
+  int CountIterableHistograms(StatisticsRecorder::HistogramIterator* iter) {
+    int count = 0;
+    for (; *iter != StatisticsRecorder::end(); ++*iter) {
+      ++count;
+    }
+    return count;
+  }
+
+  const bool use_persistent_histogram_allocator_;
+
   std::unique_ptr<StatisticsRecorder> statistics_recorder_;
+  std::unique_ptr<GlobalHistogramAllocator> old_global_allocator_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(StatisticsRecorderTest);
 };
 
-TEST_F(StatisticsRecorderTest, NotInitialized) {
+// Run all HistogramTest cases with both heap and persistent memory.
+INSTANTIATE_TEST_CASE_P(Allocator, StatisticsRecorderTest, testing::Bool());
+
+TEST_P(StatisticsRecorderTest, NotInitialized) {
   UninitializeStatisticsRecorder();
 
   ASSERT_FALSE(StatisticsRecorder::IsActive());
@@ -92,7 +118,7 @@
   EXPECT_EQ(0u, registered_ranges.size());
 }
 
-TEST_F(StatisticsRecorderTest, RegisterBucketRanges) {
+TEST_P(StatisticsRecorderTest, RegisterBucketRanges) {
   std::vector<const BucketRanges*> registered_ranges;
 
   BucketRanges* ranges1 = new BucketRanges(3);
@@ -130,7 +156,7 @@
   ASSERT_EQ(2u, registered_ranges.size());
 }
 
-TEST_F(StatisticsRecorderTest, RegisterHistogram) {
+TEST_P(StatisticsRecorderTest, RegisterHistogram) {
   // Create a Histogram that was not registered.
   Histogram* histogram = CreateHistogram("TestHistogram", 1, 1000, 10);
 
@@ -152,7 +178,7 @@
   EXPECT_EQ(1u, registered_histograms.size());
 }
 
-TEST_F(StatisticsRecorderTest, FindHistogram) {
+TEST_P(StatisticsRecorderTest, FindHistogram) {
   HistogramBase* histogram1 = Histogram::FactoryGet(
       "TestHistogram1", 1, 1000, 10, HistogramBase::kNoFlags);
   HistogramBase* histogram2 = Histogram::FactoryGet(
@@ -160,10 +186,33 @@
 
   EXPECT_EQ(histogram1, StatisticsRecorder::FindHistogram("TestHistogram1"));
   EXPECT_EQ(histogram2, StatisticsRecorder::FindHistogram("TestHistogram2"));
-  EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram") == NULL);
+  EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
+
+  // Create a new global allocator using the same memory as the old one. Any
+  // old one is kept around so the memory doesn't get released.
+  old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting();
+  if (use_persistent_histogram_allocator_) {
+    GlobalHistogramAllocator::CreateWithPersistentMemory(
+        const_cast<void*>(old_global_allocator_->data()),
+        old_global_allocator_->length(), 0, old_global_allocator_->Id(),
+        old_global_allocator_->Name());
+  }
+
+  // Reset statistics-recorder to validate operation from a clean start.
+  UninitializeStatisticsRecorder();
+  InitializeStatisticsRecorder();
+
+  if (use_persistent_histogram_allocator_) {
+    EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram1"));
+    EXPECT_TRUE(StatisticsRecorder::FindHistogram("TestHistogram2"));
+  } else {
+    EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram1"));
+    EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram2"));
+  }
+  EXPECT_FALSE(StatisticsRecorder::FindHistogram("TestHistogram"));
 }
 
-TEST_F(StatisticsRecorderTest, GetSnapshot) {
+TEST_P(StatisticsRecorderTest, GetSnapshot) {
   Histogram::FactoryGet("TestHistogram1", 1, 1000, 10, Histogram::kNoFlags);
   Histogram::FactoryGet("TestHistogram2", 1, 1000, 10, Histogram::kNoFlags);
   Histogram::FactoryGet("TestHistogram3", 1, 1000, 10, Histogram::kNoFlags);
@@ -181,7 +230,7 @@
   EXPECT_EQ(0u, snapshot.size());
 }
 
-TEST_F(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
+TEST_P(StatisticsRecorderTest, RegisterHistogramWithFactoryGet) {
   StatisticsRecorder::Histograms registered_histograms;
 
   StatisticsRecorder::GetHistograms(&registered_histograms);
@@ -227,7 +276,14 @@
   EXPECT_EQ(4u, registered_histograms.size());
 }
 
-TEST_F(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+TEST_P(StatisticsRecorderTest, RegisterHistogramWithMacros) {
+  // Macros cache pointers and so tests that use them can only be run once.
+  // Stop immediately if this test has run previously.
+  static bool already_run = false;
+  if (already_run)
+    return;
+  already_run = true;
+
   StatisticsRecorder::Histograms registered_histograms;
 
   HistogramBase* histogram = Histogram::FactoryGet(
@@ -248,7 +304,7 @@
   EXPECT_EQ(3u, registered_histograms.size());
 }
 
-TEST_F(StatisticsRecorderTest, BucketRangesSharing) {
+TEST_P(StatisticsRecorderTest, BucketRangesSharing) {
   std::vector<const BucketRanges*> ranges;
   StatisticsRecorder::GetBucketRanges(&ranges);
   EXPECT_EQ(0u, ranges.size());
@@ -266,11 +322,15 @@
   EXPECT_EQ(2u, ranges.size());
 }
 
-TEST_F(StatisticsRecorderTest, ToJSON) {
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 30);
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram1", 40);
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 30);
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram2", 40);
+TEST_P(StatisticsRecorderTest, ToJSON) {
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(30);
+  Histogram::FactoryGet("TestHistogram1", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(40);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(30);
+  Histogram::FactoryGet("TestHistogram2", 1, 1000, 50, HistogramBase::kNoFlags)
+      ->Add(40);
 
   std::string json(StatisticsRecorder::ToJSON(std::string()));
 
@@ -325,20 +385,37 @@
   EXPECT_TRUE(json.empty());
 }
 
-TEST_F(StatisticsRecorderTest, IterationTest) {
-  StatisticsRecorder::Histograms registered_histograms;
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram.IterationTest1", 30);
-  GlobalHistogramAllocator::CreateWithLocalMemory(64 << 10 /* 64 KiB */, 0, "");
-  LOCAL_HISTOGRAM_COUNTS("TestHistogram.IterationTest2", 30);
+TEST_P(StatisticsRecorderTest, IterationTest) {
+  Histogram::FactoryGet("IterationTest1", 1, 64, 16, HistogramBase::kNoFlags);
+  Histogram::FactoryGet("IterationTest2", 1, 64, 16, HistogramBase::kNoFlags);
 
   StatisticsRecorder::HistogramIterator i1 = StatisticsRecorder::begin(true);
-  EXPECT_NE(StatisticsRecorder::end(), i1);
-  EXPECT_NE(StatisticsRecorder::end(), ++i1);
-  EXPECT_EQ(StatisticsRecorder::end(), ++i1);
+  EXPECT_EQ(2, CountIterableHistograms(&i1));
 
   StatisticsRecorder::HistogramIterator i2 = StatisticsRecorder::begin(false);
-  EXPECT_NE(StatisticsRecorder::end(), i2);
-  EXPECT_EQ(StatisticsRecorder::end(), ++i2);
+  EXPECT_EQ(use_persistent_histogram_allocator_ ? 0 : 2,
+            CountIterableHistograms(&i2));
+
+  // Create a new global allocator using the same memory as the old one. Any
+  // old one is kept around so the memory doesn't get released.
+  old_global_allocator_ = GlobalHistogramAllocator::ReleaseForTesting();
+  if (use_persistent_histogram_allocator_) {
+    GlobalHistogramAllocator::CreateWithPersistentMemory(
+        const_cast<void*>(old_global_allocator_->data()),
+        old_global_allocator_->length(), 0, old_global_allocator_->Id(),
+        old_global_allocator_->Name());
+  }
+
+  // Reset statistics-recorder to validate operation from a clean start.
+  UninitializeStatisticsRecorder();
+  InitializeStatisticsRecorder();
+
+  StatisticsRecorder::HistogramIterator i3 = StatisticsRecorder::begin(true);
+  EXPECT_EQ(use_persistent_histogram_allocator_ ? 2 : 0,
+            CountIterableHistograms(&i3));
+
+  StatisticsRecorder::HistogramIterator i4 = StatisticsRecorder::begin(false);
+  EXPECT_EQ(0, CountIterableHistograms(&i4));
 }
 
 namespace {
@@ -360,7 +437,7 @@
 }  // namespace
 
 // Check that you can't overwrite the callback with another.
-TEST_F(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
+TEST_P(StatisticsRecorderTest, SetCallbackFailsWithoutHistogramTest) {
   CallbackCheckWrapper callback_wrapper;
 
   bool result = base::StatisticsRecorder::SetCallback(
@@ -375,7 +452,7 @@
 }
 
 // Check that you can't overwrite the callback with another.
-TEST_F(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
+TEST_P(StatisticsRecorderTest, SetCallbackFailsWithHistogramTest) {
   HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
                                                    HistogramBase::kNoFlags);
   EXPECT_TRUE(histogram);
@@ -402,7 +479,7 @@
 }
 
 // Check that you can't overwrite the callback with another.
-TEST_F(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
+TEST_P(StatisticsRecorderTest, ClearCallbackSuceedsWithHistogramTest) {
   HistogramBase* histogram = Histogram::FactoryGet("TestHistogram", 1, 1000, 10,
                                                    HistogramBase::kNoFlags);
   EXPECT_TRUE(histogram);
@@ -425,7 +502,7 @@
 }
 
 // Check that callback is used.
-TEST_F(StatisticsRecorderTest, CallbackUsedTest) {
+TEST_P(StatisticsRecorderTest, CallbackUsedTest) {
   {
     HistogramBase* histogram = Histogram::FactoryGet(
         "TestHistogram", 1, 1000, 10, HistogramBase::kNoFlags);
@@ -499,7 +576,7 @@
 }
 
 // Check that setting a callback before the histogram exists works.
-TEST_F(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
+TEST_P(StatisticsRecorderTest, CallbackUsedBeforeHistogramCreatedTest) {
   CallbackCheckWrapper callback_wrapper;
 
   base::StatisticsRecorder::SetCallback(
diff --git a/build/all.gyp b/build/all.gyp
index 1635f82..95d9256 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -827,6 +827,7 @@
             '../ui/android/ui_android.gyp:ui_android_unittests',
             '../ui/base/ui_base_tests.gyp:ui_base_unittests',
             '../ui/events/events_unittests.gyp:events_unittests',
+            '../ui/latency_info/latency_info_unittests.gyp:latency_info_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
             # Unit test bundles packaged as an apk.
             '../base/base.gyp:base_unittests_apk',
@@ -855,6 +856,7 @@
             '../ui/events/events_unittests.gyp:events_unittests_apk',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests_apk',
             '../ui/gl/gl_tests.gyp:gl_unittests_apk',
+            '../ui/latency_info/latency_info_unittests.gyp:latency_info_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests_apk',
           ],
           'conditions': [
@@ -1054,6 +1056,7 @@
             '../ui/events/events_unittests.gyp:events_unittests',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../ui/latency_info/latency_info_unittests.gyp:latency_info_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
             '../ui/views/views.gyp:views_unittests',
             '../url/url.gyp:url_unittests',
@@ -1157,6 +1160,7 @@
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/gl/gl_tests.gyp:gl_unittests',
             '../ui/keyboard/keyboard.gyp:keyboard_unittests',
+            '../ui/latency_info/latency_info_unittests.gyp:latency_info_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
             '../url/url.gyp:url_unittests',
           ],
@@ -1275,6 +1279,7 @@
             '../ui/events/events.gyp:*',
             '../ui/gfx/gfx_tests.gyp:gfx_unittests',
             '../ui/gl/gl_tests.gyp:gl_unittests',
+            '../ui/latency_info/latency_info.gyp:*',
             '../ui/keyboard/keyboard.gyp:*',
             '../ui/snapshot/snapshot.gyp:snapshot_unittests',
             '../ui/touch_selection/ui_touch_selection.gyp:ui_touch_selection_unittests',
diff --git a/build/android/play_services/preprocess.py b/build/android/play_services/preprocess.py
index 0705729..99c000e 100755
--- a/build/android/play_services/preprocess.py
+++ b/build/android/play_services/preprocess.py
@@ -125,7 +125,7 @@
       _ImportFromAars(config, tmp_paths, repo)
 
     _GenerateCombinedJar(tmp_paths)
-    _ProcessResources(config, tmp_paths)
+    _ProcessResources(config, tmp_paths, repo)
     _BuildOutput(config, tmp_paths, out_dir)
   finally:
     shutil.rmtree(tmp_root)
@@ -199,7 +199,7 @@
   cmd_helper.Call(['jar', '-cf', out_file_name, '-C', working_dir, '.'])
 
 
-def _ProcessResources(config, tmp_paths):
+def _ProcessResources(config, tmp_paths, repo):
   LOCALIZED_VALUES_BASE_NAME = 'values-'
   locale_whitelist = set(config.locale_whitelist)
 
@@ -216,6 +216,17 @@
       if dir_locale not in locale_whitelist:
         shutil.rmtree(res_dir)
 
+  # Reimport files from the whitelist.
+  for res_path in config.resource_whitelist:
+    for whitelisted_file in glob.glob(os.path.join(repo, res_path)):
+      resolved_file = os.path.relpath(whitelisted_file, repo)
+      rebased_res = os.path.join(tmp_paths['imported_clients'], resolved_file)
+
+      if not os.path.exists(os.path.dirname(rebased_res)):
+        os.makedirs(os.path.dirname(rebased_res))
+
+      shutil.copy(os.path.join(repo, whitelisted_file), rebased_res)
+
 
 def _BuildOutput(config, tmp_paths, out_dir):
   generation_date = datetime.utcnow()
diff --git a/build/android/play_services/utils.py b/build/android/play_services/utils.py
index 0e6d5a8..acc6cf4 100644
--- a/build/android/play_services/utils.py
+++ b/build/android/play_services/utils.py
@@ -65,6 +65,11 @@
       `//chrome/app/generated_resources.grd`
       Example: ["am", "ar", "bg", "ca", "cs"]
 
+   - resource_whitelist
+     List of strings. List of resource files to explicitely keep in the final
+     output. Use it to keep drawables for example, as we currently remove them
+     all.
+     Example: ["play-services-base/res/drawables/foobar.xml"]
   '''
   _VERSION_NUMBER_KEY = 'version_number'
 
@@ -95,6 +100,10 @@
   def locale_whitelist(self):
     return self._data.get('locale_whitelist') or []
 
+  @property
+  def resource_whitelist(self):
+    return self._data.get('resource_whitelist') or []
+
   def UpdateVersionNumber(self, new_version_number):
     '''Updates the version number and saves it in the configuration file. '''
 
diff --git a/build/args/blimp_engine.gn b/build/args/blimp_engine.gn
index 2500b30b..a5f20e3 100644
--- a/build/args/blimp_engine.gn
+++ b/build/args/blimp_engine.gn
@@ -6,6 +6,9 @@
 # gn gen out/foo
 #
 # Use gn args to add your own build preference args.
+#
+# This list must be kept in sync with the blimp list in
+# //tools/mb/mb_config.pyl.
 
 use_aura = true
 use_ozone = true
diff --git a/build/common.gypi b/build/common.gypi
index 15499765..db2739c 100644
--- a/build/common.gypi
+++ b/build/common.gypi
@@ -265,11 +265,6 @@
             'enable_topchrome_md%': 1,
           }],
 
-          # On iOS, use NSS rather than OpenSSL. See http://crbug.com/338886.
-          ['OS=="ios"', {
-            'use_openssl%': 0,
-          }],
-
           # Enable App Launcher everywhere but mobile.
           ['OS!="ios" and OS!="android"', {
             'enable_app_list%': 1,
@@ -1065,18 +1060,23 @@
           # http://crbug.com/574476
           'fastbuild%': 2,
         }],
-
-        # Enable crash reporting via Kasko.
+        # Enable hang report capture. Capture can only be enabled for 32bit
+        # Windows.
         ['OS=="win" and target_arch=="ia32" and branding=="Chrome"', {
-          # This needs to be enabled with kasko_hang_reports.
-          'kasko%': 0,
+          # Enable hang reports from the watcher process.
+          'kasko_hang_reports%': 0,
+          # Enable failed rendez-vous reports.
+          'kasko_failed_rdv_reports%': 0,
         }, {
-          'kasko%': 0,
+          # Enable hang reports from the watcher process.
+          'kasko_hang_reports%': 0,
+          # Enable failed rendez-vous reports.
+          'kasko_failed_rdv_reports%': 0,
         }],
       ],
 
-      # Enable hang reports in Kasko. Requires Kasko to be enabled.
-      'kasko_hang_reports%': 0,
+      # Kasko reporting is disabled by default, but may get enabled below.
+      'kasko%': 0,
 
       # Setting this to '0' will cause V8's startup snapshot to be
       # embedded in the binary instead of being a external files.
@@ -1228,6 +1228,7 @@
     'syzyasan%': '<(syzyasan)',
     'kasko%': '<(kasko)',
     'kasko_hang_reports%': '<(kasko_hang_reports)',
+    'kasko_failed_rdv_reports%': '<(kasko_failed_rdv_reports)',
     'syzygy_optimize%': '<(syzygy_optimize)',
     'lsan%': '<(lsan)',
     'msan%': '<(msan)',
@@ -2023,10 +2024,15 @@
           }, {
             'win_console_app%': 0,
           }],
+          # Disable hang reporting for syzyasan builds.
           ['syzyasan==1', {
-            'kasko%': 1,
-            # Disable hang reports for SyzyASAN builds.
+            # Note: override.
             'kasko_hang_reports': 0,
+            'kasko_failed_rdv_reports': 0,
+          }],
+          # Enable the Kasko reporter for syzyasan builds and hang reporting.
+          ['syzyasan==1 or kasko_hang_reports==1 or kasko_failed_rdv_reports==1', {
+            'kasko': 1,
           }],
           ['component=="shared_library" and "<(GENERATOR)"=="ninja"', {
             # Only enabled by default for ninja because it's buggy in VS.
@@ -5190,7 +5196,6 @@
           # These should end with %, but there seems to be a bug with % in
           # variables that are intended to be set to different values in
           # different targets, like these.
-          'mac_pie': 1,        # Most executables can be position-independent.
           # Strip debugging symbols from the target.
           'mac_strip': '<(mac_strip_release)',
           'conditions': [
@@ -5283,55 +5288,14 @@
             ],
           }],
           ['_type=="executable"', {
-            'postbuilds': [
-              {
-                # Arranges for data (heap) pages to be protected against
-                # code execution when running on Mac OS X 10.7 ("Lion"), and
-                # ensures that the position-independent executable (PIE) bit
-                # is set for ASLR when running on Mac OS X 10.5 ("Leopard").
-                'variables': {
-                  # Define change_mach_o_flags in a variable ending in _path
-                  # so that GYP understands it's a path and performs proper
-                  # relativization during dict merging.
-                  'change_mach_o_flags_path':
-                      'mac/change_mach_o_flags_from_xcode.sh',
-                  'change_mach_o_flags_options%': [
-                  ],
-                  'target_conditions': [
-                    ['mac_pie==0 or release_valgrind_build==1', {
-                      # Don't enable PIE if it's unwanted. It's unwanted if
-                      # the target specifies mac_pie=0 or if building for
-                      # Valgrind, because Valgrind doesn't understand slide.
-                      # See the similar mac_pie/release_valgrind_build check
-                      # below.
-                      'change_mach_o_flags_options': [
-                        '--no-pie',
-                      ],
-                    }],
-                  ],
-                },
-                'postbuild_name': 'Change Mach-O Flags',
-                'action': [
-                  '<(change_mach_o_flags_path)',
-                  '>@(change_mach_o_flags_options)',
-                ],
-              },
-            ],
-            'target_conditions': [
-              ['mac_pie==1 and release_valgrind_build==0', {
-                # Turn on position-independence (ASLR) for executables. When
-                # PIE is on for the Chrome executables, the framework will
-                # also be subject to ASLR.
-                # Don't do this when building for Valgrind, because Valgrind
-                # doesn't understand slide. TODO: Make Valgrind on Mac OS X
-                # understand slide, and get rid of the Valgrind check.
-                'xcode_settings': {
-                  'OTHER_LDFLAGS': [
-                    '-Wl,-pie',  # Position-independent executable (MH_PIE)
-                  ],
-                },
-              }],
-            ],
+            # Turn on position-independence (ASLR) for executables. When
+            # PIE is on for the Chrome executables, the framework will
+            # also be subject to ASLR.
+            'xcode_settings': {
+              'OTHER_LDFLAGS': [
+                '-Wl,-pie',  # Position-independent executable (MH_PIE)
+              ],
+            },
           }],
           ['(_type=="executable" or _type=="shared_library" or \
              _type=="loadable_module") and mac_strip!=0', {
diff --git a/build/config/BUILDCONFIG.gn b/build/config/BUILDCONFIG.gn
index 2e7f878..c36aeab 100644
--- a/build/config/BUILDCONFIG.gn
+++ b/build/config/BUILDCONFIG.gn
@@ -556,6 +556,16 @@
     }
   }
 }
+if (is_ios) {
+  set_defaults("ios_framework_bundle") {
+    configs = _shared_library_configs
+  }
+}
+if (is_mac) {
+  set_defaults("mac_framework_bundle") {
+    configs = _shared_library_configs
+  }
+}
 
 # Source set defaults (also for components in non-component mode).
 set_defaults("source_set") {
diff --git a/build/config/crypto.gni b/build/config/crypto.gni
index 7d671cf..2b15b1c 100644
--- a/build/config/crypto.gni
+++ b/build/config/crypto.gni
@@ -12,9 +12,7 @@
 # to set up feature flags.
 
 declare_args() {
-  # Use OpenSSL instead of NSS. This is used for all platforms but iOS. (See
-  # http://crbug.com/338886).
-  use_openssl = !is_ios
+  use_openssl = true
 }
 
 # True when we're using OpenSSL for representing certificates. When targeting
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 604e7ab..0abd252 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -76,8 +76,8 @@
           "-s=PRODUCT_NAME=$_output_name",
           "-s=XCODE_BUILD=$xcode_build",
           "-s=XCODE_VERSION=$xcode_version",
-          "-o=" + rebase_path(outputs[0], root_build_dir),
-        ] + rebase_path(sources, root_build_dir)
+          "-o=" + rebase_path(outputs[0], root_out_dir),
+        ] + rebase_path(sources, root_out_dir)
     args = [ "@{{response_file_name}}" ]
   }
 
@@ -110,21 +110,11 @@
                              "visibility",
                            ])
 
-    output_name = rebase_path("$target_gen_dir/$_output_name", root_build_dir)
+    output_name = rebase_path("$target_gen_dir/$_output_name", root_out_dir)
     if (!defined(libs)) {
       libs = []
     }
     libs += [ "UIKit.framework" ]
-
-    # TODO(crbug.com/599203) - iossim should probably be a data dependency
-    # of the create_bundle(target_name) target instead but at the moment
-    # create_bundle() is ignoring data_deps.
-    if (use_ios_simulator) {
-      if (!defined(data_deps)) {
-        data_deps = []
-      }
-      data_deps += [ "//testing/iossim(${host_toolchain})" ]
-    }
   }
 
   bundle_data(_bundle_data_executable) {
@@ -159,6 +149,13 @@
       ":$_bundle_data_info_plist",
     ]
 
+    if (use_ios_simulator) {
+      if (!defined(data_deps)) {
+        data_deps = []
+      }
+      data_deps += [ "//testing/iossim(${host_toolchain})" ]
+    }
+
     bundle_root_dir = "$root_out_dir/$_output_name.app"
     bundle_resources_dir = bundle_root_dir
     bundle_executable_dir = bundle_root_dir
@@ -210,7 +207,7 @@
       "--output",
       rebase_path("$target_gen_dir/$_nib_filename"),
       "--input",
-      rebase_path(invoker.source, root_build_dir),
+      rebase_path(invoker.source, root_out_dir),
     ]
   }
 
@@ -246,10 +243,110 @@
 #         structure will not be created, and build output will go directly
 #         into the framework subdirectory.
 #
+#     public_headers:
+#         (optional) list of paths to header file that needs to be copied
+#         into the framework bundle Headers subdirectory. If omitted or
+#         empty then the Headers subdirectory is not created.
+#
+#     sources
+#         (optional) list of files. Needs to be defined and non-empty if
+#         public_headers is defined and non-empty.
+#
 # See "gn help shared_library" for more information on arguments supported
 # by shared library target.
 template("ios_framework_bundle") {
+  if (defined(invoker.public_headers) && invoker.public_headers != []) {
+    assert(defined(invoker.sources) && invoker.sources != [],
+           "sources must be set for $target_name when public_headers is set")
+
+    _target_name = target_name
+    _output_name = target_name
+    if (defined(invoker.output_name)) {
+      _output_name = invoker.output_name
+    }
+
+    _public_headers = invoker.public_headers
+    _framework_name = _output_name + ".framework"
+    _framework_root = "$root_out_dir/$_framework_name"
+
+    _header_map_filename = "$target_gen_dir/$_output_name.headers.hmap"
+    _framework_headers_target = _target_name + "_framework_headers"
+
+    _compile_headers_map_target = _target_name + "_compile_headers_map"
+    action(_compile_headers_map_target) {
+      visibility = [ ":$_framework_headers_target" ]
+      script = "$root_out_dir/gyp-mac-tool"
+      outputs = [
+        _header_map_filename,
+      ]
+
+      # The header map generation only wants the list of headers, not all of
+      # sources, so filter any non-header source files from "sources". It is
+      # less error prone that having the developer duplicate the list of all
+      # headers in addition to "sources".
+      set_sources_assignment_filter([
+                                      "*.c",
+                                      "*.cc",
+                                      "*.cpp",
+                                      "*.m",
+                                      "*.mm",
+                                    ])
+      sources = invoker.sources
+      set_sources_assignment_filter([])
+
+      args = [
+               "compile-ios-framework-header-map",
+               rebase_path(_header_map_filename),
+               rebase_path(_framework_root, root_out_dir),
+             ] + rebase_path(sources, root_out_dir)
+    }
+
+    _create_module_map_target = _target_name + "_module_map"
+    action(_create_module_map_target) {
+      visibility = [ ":$_framework_headers_target" ]
+      script = "$root_out_dir/gyp-mac-tool"
+      outputs = [
+        "$_framework_root/Modules/module.modulemap",
+      ]
+      args = [
+        "package-ios-framework",
+        rebase_path("$_framework_root", root_out_dir),
+      ]
+    }
+
+    _copy_public_headers_target = _target_name + "_copy_public_headers"
+    copy(_copy_public_headers_target) {
+      visibility = [ ":$_framework_headers_target" ]
+      sources = _public_headers
+      outputs = [
+        "$_framework_root/Headers/{{source_file_part}}",
+      ]
+    }
+
+    _headers_map_config = _target_name + "_headers_map"
+    config(_headers_map_config) {
+      visibility = [ ":$_target_name" ]
+      include_dirs = [ _header_map_filename ]
+    }
+
+    group(_framework_headers_target) {
+      deps = [
+        ":$_compile_headers_map_target",
+        ":$_copy_public_headers_target",
+        ":$_create_module_map_target",
+      ]
+    }
+  }
+
   framework_bundle(target_name) {
-    forward_variables_from(invoker, "*")
+    forward_variables_from(invoker, "*", [ "public_headers" ])
+
+    if (defined(_public_headers)) {
+      configs += [ ":$_headers_map_config" ]
+      if (!defined(deps)) {
+        deps = []
+      }
+      deps += [ ":$_framework_headers_target" ]
+    }
   }
 }
diff --git a/build/config/win/BUILD.gn b/build/config/win/BUILD.gn
index db3cdca..f48b4640d 100644
--- a/build/config/win/BUILD.gn
+++ b/build/config/win/BUILD.gn
@@ -299,7 +299,12 @@
 
 incremental_linking_on_switch = [ "/INCREMENTAL" ]
 incremental_linking_off_switch = [ "/INCREMENTAL:NO" ]
-if (is_debug) {
+
+# MSVC2015's incremental linker complains about clang's .obj files sometimes,
+# https://crbug.com/595702.  Disable incremental linking with clang for now.
+# TODO(thakis): Remove this once that problem is fixed, or when the win_clang
+# bot uses lld.
+if (is_debug && !is_clang) {
   default_incremental_linking_switch = incremental_linking_on_switch
 } else {
   default_incremental_linking_switch = incremental_linking_off_switch
diff --git a/build/mac/change_mach_o_flags.py b/build/mac/change_mach_o_flags.py
deleted file mode 100755
index c2aeaec9..0000000
--- a/build/mac/change_mach_o_flags.py
+++ /dev/null
@@ -1,273 +0,0 @@
-#!/usr/bin/env python
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-"""Usage: change_mach_o_flags.py [--executable-heap] [--no-pie] <executablepath>
-
-Arranges for the executable at |executable_path| to have its data (heap)
-pages protected to prevent execution on Mac OS X 10.7 ("Lion"), and to have
-the PIE (position independent executable) bit set to enable ASLR (address
-space layout randomization). With --executable-heap or --no-pie, the
-respective bits are cleared instead of set, making the heap executable or
-disabling PIE/ASLR.
-
-This script is able to operate on thin (single-architecture) Mach-O files
-and fat (universal, multi-architecture) files. When operating on fat files,
-it will set or clear the bits for each architecture contained therein.
-
-NON-EXECUTABLE HEAP
-
-Traditionally in Mac OS X, 32-bit processes did not have data pages set to
-prohibit execution. Although user programs could call mprotect and
-mach_vm_protect to deny execution of code in data pages, the kernel would
-silently ignore such requests without updating the page tables, and the
-hardware would happily execute code on such pages. 64-bit processes were
-always given proper hardware protection of data pages. This behavior was
-controllable on a system-wide level via the vm.allow_data_exec sysctl, which
-is set by default to 1. The bit with value 1 (set by default) allows code
-execution on data pages for 32-bit processes, and the bit with value 2
-(clear by default) does the same for 64-bit processes.
-
-In Mac OS X 10.7, executables can "opt in" to having hardware protection
-against code execution on data pages applied. This is done by setting a new
-bit in the |flags| field of an executable's |mach_header|. When
-MH_NO_HEAP_EXECUTION is set, proper protections will be applied, regardless
-of the setting of vm.allow_data_exec. See xnu-1699.22.73/osfmk/vm/vm_map.c
-override_nx and xnu-1699.22.73/bsd/kern/mach_loader.c load_machfile.
-
-The Apple toolchain has been revised to set the MH_NO_HEAP_EXECUTION when
-producing executables, provided that -allow_heap_execute is not specified
-at link time. Only linkers shipping with Xcode 4.0 and later (ld64-123.2 and
-later) have this ability. See ld64-123.2.1/src/ld/Options.cpp
-Options::reconfigureDefaults() and
-ld64-123.2.1/src/ld/HeaderAndLoadCommands.hpp
-HeaderAndLoadCommandsAtom<A>::flags().
-
-This script sets the MH_NO_HEAP_EXECUTION bit on Mach-O executables. It is
-intended for use with executables produced by a linker that predates Apple's
-modifications to set this bit itself. It is also useful for setting this bit
-for non-i386 executables, including x86_64 executables. Apple's linker only
-sets it for 32-bit i386 executables, presumably under the assumption that
-the value of vm.allow_data_exec is set in stone. However, if someone were to
-change vm.allow_data_exec to 2 or 3, 64-bit x86_64 executables would run
-without hardware protection against code execution on data pages. This
-script can set the bit for x86_64 executables, guaranteeing that they run
-with appropriate protection even when vm.allow_data_exec has been tampered
-with.
-
-POSITION-INDEPENDENT EXECUTABLES/ADDRESS SPACE LAYOUT RANDOMIZATION
-
-This script sets or clears the MH_PIE bit in an executable's Mach-O header,
-enabling or disabling position independence on Mac OS X 10.5 and later.
-Processes running position-independent executables have varying levels of
-ASLR protection depending on the OS release. The main executable's load
-address, shared library load addresess, and the heap and stack base
-addresses may be randomized. Position-independent executables are produced
-by supplying the -pie flag to the linker (or defeated by supplying -no_pie).
-Executables linked with a deployment target of 10.7 or higher have PIE on
-by default.
-
-This script is never strictly needed during the build to enable PIE, as all
-linkers used are recent enough to support -pie. However, it's used to
-disable the PIE bit as needed on already-linked executables.
-"""
-
-import optparse
-import os
-import struct
-import sys
-
-
-# <mach-o/fat.h>
-FAT_MAGIC = 0xcafebabe
-FAT_CIGAM = 0xbebafeca
-
-# <mach-o/loader.h>
-MH_MAGIC = 0xfeedface
-MH_CIGAM = 0xcefaedfe
-MH_MAGIC_64 = 0xfeedfacf
-MH_CIGAM_64 = 0xcffaedfe
-MH_EXECUTE = 0x2
-MH_PIE = 0x00200000
-MH_NO_HEAP_EXECUTION = 0x01000000
-
-
-class MachOError(Exception):
-  """A class for exceptions thrown by this module."""
-
-  pass
-
-
-def CheckedSeek(file, offset):
-  """Seeks the file-like object at |file| to offset |offset| and raises a
-  MachOError if anything funny happens."""
-
-  file.seek(offset, os.SEEK_SET)
-  new_offset = file.tell()
-  if new_offset != offset:
-    raise MachOError, \
-          'seek: expected offset %d, observed %d' % (offset, new_offset)
-
-
-def CheckedRead(file, count):
-  """Reads |count| bytes from the file-like |file| object, raising a
-  MachOError if any other number of bytes is read."""
-
-  bytes = file.read(count)
-  if len(bytes) != count:
-    raise MachOError, \
-          'read: expected length %d, observed %d' % (count, len(bytes))
-
-  return bytes
-
-
-def ReadUInt32(file, endian):
-  """Reads an unsinged 32-bit integer from the file-like |file| object,
-  treating it as having endianness specified by |endian| (per the |struct|
-  module), and returns it as a number. Raises a MachOError if the proper
-  length of data can't be read from |file|."""
-
-  bytes = CheckedRead(file, 4)
-
-  (uint32,) = struct.unpack(endian + 'I', bytes)
-  return uint32
-
-
-def ReadMachHeader(file, endian):
-  """Reads an entire |mach_header| structure (<mach-o/loader.h>) from the
-  file-like |file| object, treating it as having endianness specified by
-  |endian| (per the |struct| module), and returns a 7-tuple of its members
-  as numbers. Raises a MachOError if the proper length of data can't be read
-  from |file|."""
-
-  bytes = CheckedRead(file, 28)
-
-  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
-      struct.unpack(endian + '7I', bytes)
-  return magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags
-
-
-def ReadFatArch(file):
-  """Reads an entire |fat_arch| structure (<mach-o/fat.h>) from the file-like
-  |file| object, treating it as having endianness specified by |endian|
-  (per the |struct| module), and returns a 5-tuple of its members as numbers.
-  Raises a MachOError if the proper length of data can't be read from
-  |file|."""
-
-  bytes = CheckedRead(file, 20)
-
-  cputype, cpusubtype, offset, size, align = struct.unpack('>5I', bytes)
-  return cputype, cpusubtype, offset, size, align
-
-
-def WriteUInt32(file, uint32, endian):
-  """Writes |uint32| as an unsinged 32-bit integer to the file-like |file|
-  object, treating it as having endianness specified by |endian| (per the
-  |struct| module)."""
-
-  bytes = struct.pack(endian + 'I', uint32)
-  assert len(bytes) == 4
-
-  file.write(bytes)
-
-
-def HandleMachOFile(file, options, offset=0):
-  """Seeks the file-like |file| object to |offset|, reads its |mach_header|,
-  and rewrites the header's |flags| field if appropriate. The header's
-  endianness is detected. Both 32-bit and 64-bit Mach-O headers are supported
-  (mach_header and mach_header_64). Raises MachOError if used on a header that
-  does not have a known magic number or is not of type MH_EXECUTE. The
-  MH_PIE and MH_NO_HEAP_EXECUTION bits are set or cleared in the |flags| field
-  according to |options| and written to |file| if any changes need to be made.
-  If already set or clear as specified by |options|, nothing is written."""
-
-  CheckedSeek(file, offset)
-  magic = ReadUInt32(file, '<')
-  if magic == MH_MAGIC or magic == MH_MAGIC_64:
-    endian = '<'
-  elif magic == MH_CIGAM or magic == MH_CIGAM_64:
-    endian = '>'
-  else:
-    raise MachOError, \
-          'Mach-O file at offset %d has illusion of magic' % offset
-
-  CheckedSeek(file, offset)
-  magic, cputype, cpusubtype, filetype, ncmds, sizeofcmds, flags = \
-      ReadMachHeader(file, endian)
-  assert magic == MH_MAGIC or magic == MH_MAGIC_64
-  if filetype != MH_EXECUTE:
-    raise MachOError, \
-          'Mach-O file at offset %d is type 0x%x, expected MH_EXECUTE' % \
-              (offset, filetype)
-
-  original_flags = flags
-
-  if options.no_heap_execution:
-    flags |= MH_NO_HEAP_EXECUTION
-  else:
-    flags &= ~MH_NO_HEAP_EXECUTION
-
-  if options.pie:
-    flags |= MH_PIE
-  else:
-    flags &= ~MH_PIE
-
-  if flags != original_flags:
-    CheckedSeek(file, offset + 24)
-    WriteUInt32(file, flags, endian)
-
-
-def HandleFatFile(file, options, fat_offset=0):
-  """Seeks the file-like |file| object to |offset| and loops over its
-  |fat_header| entries, calling HandleMachOFile for each."""
-
-  CheckedSeek(file, fat_offset)
-  magic = ReadUInt32(file, '>')
-  assert magic == FAT_MAGIC
-
-  nfat_arch = ReadUInt32(file, '>')
-
-  for index in xrange(0, nfat_arch):
-    cputype, cpusubtype, offset, size, align = ReadFatArch(file)
-    assert size >= 28
-
-    # HandleMachOFile will seek around. Come back here after calling it, in
-    # case it sought.
-    fat_arch_offset = file.tell()
-    HandleMachOFile(file, options, offset)
-    CheckedSeek(file, fat_arch_offset)
-
-
-def main(me, args):
-  parser = optparse.OptionParser('%prog [options] <executable_path>')
-  parser.add_option('--executable-heap', action='store_false',
-                    dest='no_heap_execution', default=True,
-                    help='Clear the MH_NO_HEAP_EXECUTION bit')
-  parser.add_option('--no-pie', action='store_false',
-                    dest='pie', default=True,
-                    help='Clear the MH_PIE bit')
-  (options, loose_args) = parser.parse_args(args)
-  if len(loose_args) != 1:
-    parser.print_usage()
-    return 1
-
-  executable_path = loose_args[0]
-  executable_file = open(executable_path, 'rb+')
-
-  magic = ReadUInt32(executable_file, '<')
-  if magic == FAT_CIGAM:
-    # Check FAT_CIGAM and not FAT_MAGIC because the read was little-endian.
-    HandleFatFile(executable_file, options)
-  elif magic == MH_MAGIC or magic == MH_CIGAM or \
-      magic == MH_MAGIC_64 or magic == MH_CIGAM_64:
-    HandleMachOFile(executable_file, options)
-  else:
-    raise MachOError, '%s is not a Mach-O or fat file' % executable_file
-
-  executable_file.close()
-  return 0
-
-
-if __name__ == '__main__':
-  sys.exit(main(sys.argv[0], sys.argv[1:]))
diff --git a/build/mac/change_mach_o_flags_from_xcode.sh b/build/mac/change_mach_o_flags_from_xcode.sh
deleted file mode 100755
index 1824f8d..0000000
--- a/build/mac/change_mach_o_flags_from_xcode.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-# Copyright (c) 2011 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# This is a small wrapper script around change_mach_o_flags.py allowing it to
-# be invoked easily from Xcode. change_mach_o_flags.py expects its arguments
-# on the command line, but Xcode puts its parameters in the environment.
-
-set -e
-
-exec "$(dirname "${0}")/change_mach_o_flags.py" \
-     "${@}" \
-     "${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}"
diff --git a/build_overrides/v8.gni b/build_overrides/v8.gni
index 9e608c9..c39f47e3 100644
--- a/build_overrides/v8.gni
+++ b/build_overrides/v8.gni
@@ -9,9 +9,6 @@
 # TODO(sky): nuke this. Temporary while sorting out http://crbug.com/465456.
 enable_correct_v8_arch = false
 
-# TODO: Set v8_use_external_startup_data to true on Windows and iOS to match
-# GYP.
-# iOS - http://crbug.com/545676
 v8_use_external_startup_data = !is_ios
 
 # Turns on compiler optimizations in V8 in Debug build.
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index f1f05f5..984b76f 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -554,10 +554,10 @@
     "//gpu",
     "//gpu/command_buffer/client:gles2_interface",
     "//media",
-    "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
+    "//ui/latency_info",
   ]
 
   defines = [ "CC_IMPLEMENTATION=1" ]
@@ -952,12 +952,12 @@
     "//media",
     "//testing/gmock",
     "//testing/gtest",
-    "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx:test_support",
     "//ui/gfx/geometry",
     "//ui/gl",
     "//ui/gl:test_support",
+    "//ui/latency_info",
   ]
 
   data_deps = [
diff --git a/cc/DEPS b/cc/DEPS
index f1bdb3f..93452863 100644
--- a/cc/DEPS
+++ b/cc/DEPS
@@ -15,7 +15,7 @@
   "+third_party/khronos/GLES2/gl2.h",
   "+third_party/khronos/GLES2/gl2ext.h",
   "+third_party/skia/include",
-  "+ui/events/latency_info.h",
+  "+ui/latency_info",
   "+ui/gfx",
   "+ui/gl",
   "-cc/blink",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 69ab8395..4e6a0d88 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -19,10 +19,10 @@
         '<(DEPTH)/media/media.gyp:media',
         '<(DEPTH)/skia/skia.gyp:skia',
         '<(DEPTH)/third_party/protobuf/protobuf.gyp:protobuf_lite',
-        '<(DEPTH)/ui/events/events.gyp:events_base',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
         '<(DEPTH)/ui/gl/gl.gyp:gl',
+        "<(DEPTH)/ui/latency_info/latency_info.gyp:latency_info",
       ],
       'variables': {
         'optimize': 'max',
@@ -667,9 +667,9 @@
         '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
         '<(DEPTH)/gpu/gpu.gyp:gpu',
         '<(DEPTH)/skia/skia.gyp:skia',
-        '<(DEPTH)/ui/events/events.gyp:events_base',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx',
         '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry',
+        "<(DEPTH)/ui/latency_info/latency_info.gyp:latency_info",
       ],
       'defines': [
         'CC_SURFACES_IMPLEMENTATION=1',
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index fb5d987..b2aec9f 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -330,9 +330,9 @@
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/protobuf/protobuf.gyp:protobuf_lite',
-        '../ui/events/events.gyp:events_base',
         '../ui/gfx/gfx.gyp:gfx',
         '../ui/gfx/gfx.gyp:gfx_geometry',
+        '../ui/latency_info/latency_info.gyp:latency_info',
         'cc.gyp:cc',
         'cc.gyp:cc_proto',
         'cc.gyp:cc_surfaces',
diff --git a/cc/input/main_thread_scrolling_reason.h b/cc/input/main_thread_scrolling_reason.h
index 1f384eb..ea94631c81 100644
--- a/cc/input/main_thread_scrolling_reason.h
+++ b/cc/input/main_thread_scrolling_reason.h
@@ -19,6 +19,7 @@
   enum : uint32_t { kScrollbarScrolling = 1 << 3 };
   enum : uint32_t { kPageOverlay = 1 << 4 };
   enum : uint32_t { kAnimatingScrollOnMainThread = 1 << 13 };
+  enum : uint32_t { kHasStickyPositionObjects = 1 << 14 };
 
   // Transient scrolling reasons. These are computed for each scroll begin.
   enum : uint32_t { kNonFastScrollableRegion = 1 << 5 };
@@ -31,7 +32,7 @@
   enum : uint32_t { kPageBasedScrolling = 1 << 12 };
 
   // The number of flags in this struct (excluding itself).
-  enum : uint32_t { kMainThreadScrollingReasonCount = 15 };
+  enum : uint32_t { kMainThreadScrollingReasonCount = 16 };
 
   // Returns true if the given MainThreadScrollingReason can be set by the main
   // thread.
@@ -39,7 +40,8 @@
     uint32_t reasons_set_by_main_thread =
         kNotScrollingOnMain | kHasBackgroundAttachmentFixedObjects |
         kHasNonLayerViewportConstrainedObjects | kThreadedScrollingDisabled |
-        kScrollbarScrolling | kPageOverlay | kAnimatingScrollOnMainThread;
+        kScrollbarScrolling | kPageOverlay | kAnimatingScrollOnMainThread |
+        kHasStickyPositionObjects;
     return (reasons & reasons_set_by_main_thread) == reasons;
   }
 
diff --git a/cc/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index 54b2047..c73499d 100644
--- a/cc/output/compositor_frame_metadata.h
+++ b/cc/output/compositor_frame_metadata.h
@@ -13,9 +13,9 @@
 #include "cc/output/viewport_selection_bound.h"
 #include "cc/surfaces/surface_id.h"
 #include "third_party/skia/include/core/SkColor.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size_f.h"
 #include "ui/gfx/geometry/vector2d_f.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace cc {
 
diff --git a/cc/output/latency_info_swap_promise.h b/cc/output/latency_info_swap_promise.h
index 23a1c862..4b59159 100644
--- a/cc/output/latency_info_swap_promise.h
+++ b/cc/output/latency_info_swap_promise.h
@@ -9,7 +9,7 @@
 
 #include "base/compiler_specific.h"
 #include "cc/output/swap_promise.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace cc {
 
diff --git a/cc/quads/draw_polygon.cc b/cc/quads/draw_polygon.cc
index b0b6b4a..26b5310 100644
--- a/cc/quads/draw_polygon.cc
+++ b/cc/quads/draw_polygon.cc
@@ -45,6 +45,8 @@
     points_.push_back(in_points[i]);
   }
   normal_ = normal;
+  DCHECK_LE((ConstructNormal(), (normal_ - normal).Length()),
+            normalized_threshold);
 }
 
 // This takes the original DrawQuad that this polygon should be based on,
@@ -72,6 +74,7 @@
   for (int i = 0; i < num_vertices_in_clipped_quad; i++) {
     points_.push_back(points[i]);
   }
+  transform.TransformVector(&normal_);
   ConstructNormal();
 }
 
@@ -98,18 +101,22 @@
 // Averaging a few near diagonal cross products is pretty good in that case.
 //
 void DrawPolygon::ConstructNormal() {
-  normal_.set_x(0.0f);
-  normal_.set_y(0.0f);
-  normal_.set_z(0.0f);
+  gfx::Vector3dF new_normal(0.0f, 0.0f, 0.0f);
   int delta = points_.size() / 2;
   for (size_t i = 1; i + delta < points_.size(); i++) {
-    normal_ +=
+    new_normal +=
         CrossProduct(points_[i] - points_[0], points_[i + delta] - points_[0]);
   }
-  float normal_magnitude = normal_.Length();
-  if (normal_magnitude != 0 && normal_magnitude != 1) {
-    normal_.Scale(1.0f / normal_magnitude);
+  float normal_magnitude = new_normal.Length();
+  // Here we constrain the new normal to point in the same sense as the old one.
+  // This allows us to handle winding-reversing transforms better.
+  if (gfx::DotProduct(normal_, new_normal) < 0.0) {
+    normal_magnitude *= -1.0;
   }
+  if (normal_magnitude != 0 && normal_magnitude != 1) {
+    new_normal.Scale(1.0f / normal_magnitude);
+  }
+  normal_ = new_normal;
 }
 
 #if defined(OS_WIN)
@@ -243,6 +250,7 @@
 // be transformed along with the vertices.
 void DrawPolygon::TransformToScreenSpace(const gfx::Transform& transform) {
   ApplyTransform(transform);
+  transform.TransformVector(&normal_);
   ConstructNormal();
 }
 
diff --git a/cc/quads/draw_polygon_unittest.cc b/cc/quads/draw_polygon_unittest.cc
index 635ee31..884777f 100644
--- a/cc/quads/draw_polygon_unittest.cc
+++ b/cc/quads/draw_polygon_unittest.cc
@@ -30,8 +30,12 @@
 #define CREATE_NEW_DRAW_POLYGON(name, points_vector, normal, polygon_id) \
   DrawPolygon name(NULL, points_vector, normal, polygon_id)
 
-#define CREATE_TEST_DRAW_POLYGON(name, points_vector, polygon_id)             \
-  DrawPolygon name(NULL, points_vector, gfx::Vector3dF(1, 2, 3), polygon_id); \
+#define CREATE_TEST_DRAW_FORWARD_POLYGON(name, points_vector, id)        \
+  DrawPolygon name(NULL, points_vector, gfx::Vector3dF(0, 0, 1.0f), id); \
+  name.RecomputeNormalForTesting()
+
+#define CREATE_TEST_DRAW_REVERSE_POLYGON(name, points_vector, id)         \
+  DrawPolygon name(NULL, points_vector, gfx::Vector3dF(0, 0, -1.0f), id); \
   name.RecomputeNormalForTesting()
 
 #define EXPECT_FLOAT_WITHIN_EPSILON_OF(a, b) \
@@ -70,7 +74,7 @@
   vertices.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f));
   vertices.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f));
 
-  CREATE_TEST_DRAW_POLYGON(polygon, vertices, 1);
+  CREATE_TEST_DRAW_FORWARD_POLYGON(polygon, vertices, 1);
   EXPECT_NORMAL(polygon, 0.0f, 0.0f, 1.0f);
 }
 
@@ -83,7 +87,7 @@
   vertices.push_back(gfx::Point3F(10.0f, 0.0f, 0.0f));
   vertices.push_back(gfx::Point3F(10.0f, 10.0f, 0.0f));
 
-  CREATE_TEST_DRAW_POLYGON(polygon, vertices, 1);
+  CREATE_TEST_DRAW_FORWARD_POLYGON(polygon, vertices, 1);
   EXPECT_NORMAL(polygon, 0.0f, 0.0f, 1.0f);
 }
 
@@ -93,7 +97,7 @@
   vertices.push_back(gfx::Point3F(5000.0f, 0.0f, 0.0f));
   vertices.push_back(gfx::Point3F(10000.0f, 1.0f, 0.0f));
 
-  CREATE_TEST_DRAW_POLYGON(polygon, vertices, 2);
+  CREATE_TEST_DRAW_FORWARD_POLYGON(polygon, vertices, 2);
   EXPECT_NORMAL(polygon, 0.0f, 0.0f, 1.0f);
 }
 
@@ -106,10 +110,10 @@
     vertices_d.push_back(gfx::Point3F(cos(i * M_PI / 50) + 99.0f,
                                       sin(i * M_PI / 50) + 99.0f, 100.0f));
   }
-  CREATE_TEST_DRAW_POLYGON(polygon_c, vertices_c, 3);
+  CREATE_TEST_DRAW_FORWARD_POLYGON(polygon_c, vertices_c, 3);
   EXPECT_NORMAL(polygon_c, 0.0f, 0.0f, 1.0f);
 
-  CREATE_TEST_DRAW_POLYGON(polygon_d, vertices_d, 4);
+  CREATE_TEST_DRAW_FORWARD_POLYGON(polygon_d, vertices_d, 4);
   EXPECT_NORMAL(polygon_c, 0.0f, 0.0f, 1.0f);
 }
 
@@ -159,8 +163,7 @@
   EXPECT_NORMAL(polygon_b, 0.0f, 0.0f, 1.0f);
 }
 
-// Bug https://bugs.chromium.org/p/chromium/issues/detail?id=595820
-TEST(DrawPolygonConstructionTest, DISABLED_InvertXNormal) {
+TEST(DrawPolygonConstructionTest, InvertXNormal) {
   gfx::RectF src(-0.1f, -10.0f, 0.2f, 20.0f);
 
   gfx::Transform transform(-1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
@@ -169,7 +172,7 @@
   EXPECT_NORMAL(polygon_d, 0.0f, 0.0f, 1.0f);
 }
 
-TEST(DrawPolygonConstructionTest, DISABLED_InvertYNormal) {
+TEST(DrawPolygonConstructionTest, InvertYNormal) {
   gfx::RectF src(-0.1f, -10.0f, 0.2f, 20.0f);
 
   gfx::Transform transform(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1);
@@ -178,7 +181,7 @@
   EXPECT_NORMAL(polygon_d, 0.0f, 0.0f, 1.0f);
 }
 
-TEST(DrawPolygonConstructionTest, DISABLED_InvertZNormal) {
+TEST(DrawPolygonConstructionTest, InvertZNormal) {
   gfx::RectF src(-0.1f, -10.0f, 0.2f, 20.0f);
 
   gfx::Transform transform(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1);
@@ -370,13 +373,8 @@
   vertices_a.push_back(gfx::Point3F(1.0f, 0.0f, 1.0f));
   vertices_a.push_back(gfx::Point3F(-1.0f, 0.0f, -1.0f));
   vertices_a.push_back(gfx::Point3F(0.0f, 1.0f, 0.0f));
-  CREATE_NEW_DRAW_POLYGON(
-      polygon_a, vertices_a, gfx::Vector3dF(0.707107f, 0.0f, -0.707107f), 0);
-  // Check we believe your little white lie.
-  EXPECT_NORMAL(polygon_a, 0.707107f, 0.0f, -0.707107f);
-
-  polygon_a.RecomputeNormalForTesting();
-  // Check that we recompute it more accurately.
+  CREATE_NEW_DRAW_POLYGON(polygon_a, vertices_a,
+                          gfx::Vector3dF(sqrt(2) / 2, 0.0f, -sqrt(2) / 2), 0);
   EXPECT_NORMAL(polygon_a, sqrt(2) / 2, 0.0f, -sqrt(2) / 2);
 
   gfx::Transform transform;
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index 1c5ca5c..c64d96e5 100644
--- a/cc/surfaces/BUILD.gn
+++ b/cc/surfaces/BUILD.gn
@@ -55,9 +55,9 @@
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/command_buffer/common",
     "//skia",
-    "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
+    "//ui/latency_info",
   ]
 
   if (is_android && !is_debug) {
diff --git a/cc/surfaces/display.h b/cc/surfaces/display.h
index cb8e898b..3ab9cefb 100644
--- a/cc/surfaces/display.h
+++ b/cc/surfaces/display.h
@@ -18,7 +18,7 @@
 #include "cc/surfaces/surface_id.h"
 #include "cc/surfaces/surface_manager.h"
 #include "cc/surfaces/surfaces_export.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace gpu {
 class GpuMemoryBufferManager;
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index c6c9967..ddf6680e 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4532,6 +4532,9 @@
   <message name="IDS_KEYBOARD_OVERLAY_CLOSE_WINDOW" desc="The text in the keyboard overlay to explain the shortcut.">
     Close window
   </message>
+  <message name="IDS_KEYBOARD_OVERLAY_CONTEXT_MENU" desc="The text in the keyboard overlay to explain the shortcut.">
+    Context menu
+  </message>
   <message name="IDS_KEYBOARD_OVERLAY_COPY" desc="The text in the keyboard overlay to explain the shortcut.">
     Copy
   </message>
diff --git a/chrome/app/main_dll_loader_win.cc b/chrome/app/main_dll_loader_win.cc
index 8d8f978..83415401 100644
--- a/chrome/app/main_dll_loader_win.cc
+++ b/chrome/app/main_dll_loader_win.cc
@@ -223,13 +223,7 @@
     RecordDidRun(dll_path);
 
     // Launch the watcher process if stats collection consent has been granted.
-#if defined(GOOGLE_CHROME_BUILD)
-    const bool stats_collection_consent =
-        GoogleUpdateSettings::GetCollectStatsConsent();
-#else
-    const bool stats_collection_consent = false;
-#endif
-    if (stats_collection_consent) {
+    if (crash_reporter::GetUploadsEnabled()) {
       base::FilePath exe_path;
       if (PathService::Get(base::FILE_EXE, &exe_path)) {
         chrome_watcher_client_.reset(new ChromeWatcherClient(
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index d22da25..bba41acc 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -8,6 +8,7 @@
 import("//build/config/ui.gni")
 import("//chrome/common/features.gni")
 import("//media/media_options.gni")
+import("//third_party/kasko/kasko.gni")
 import("//third_party/protobuf/proto_library.gni")
 
 # //build/config/android/rules.gni imports //tools/grit/grit_rule.gni, which
@@ -646,6 +647,13 @@
       "//components/version_info:generate_version_info",
     ]
   }
+  if (is_win && enable_kasko_failed_rdv_reports) {
+    sources += [
+      "//chrome/app/chrome_crash_reporter_client.cc",
+      "//chrome/app/chrome_crash_reporter_client.h",
+    ]
+    deps += [ "//components/crash/content/app:lib" ]
+  }
   if (use_nss_certs) {
     sources +=
         rebase_path(gypi_values.chrome_browser_nss_sources, ".", "//chrome")
@@ -829,6 +837,7 @@
     deps += [
       ":chrome_process_finder",
       "//chrome/chrome_watcher:client",
+      "//chrome/chrome_watcher:kasko_util",
       "//chrome/common:version_header",
       "//chrome/installer/util:strings",
       "//chrome_elf",
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 99f00264..2a0e2aa 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1380,7 +1380,7 @@
 }
 
 // TODO(crbug.com/602954) Test is flaky.
-#if defined(OS_WIN)
+#if defined(OS_WIN) || defined(OS_MACOSX)
 #define MAYBE_TopLevelWebContentsTracksCorrectly \
   DISABLED_TopLevelWebContentsTracksCorrectly
 #else
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index d0a8804..0b5c718 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -291,6 +291,8 @@
 #endif
 
 #if defined(ENABLE_WEBRTC)
+#include "chrome/browser/media/audio_debug_recordings_handler.h"
+#include "chrome/browser/media/webrtc_event_log_handler.h"
 #include "chrome/browser/media/webrtc_logging_handler_host.h"
 #endif
 
@@ -949,8 +951,22 @@
       new WebRtcLoggingHandlerHost(id, profile,
                                    g_browser_process->webrtc_log_uploader());
   host->AddFilter(webrtc_logging_handler_host);
-  host->SetUserData(host, new base::UserDataAdapter<WebRtcLoggingHandlerHost>(
-      webrtc_logging_handler_host));
+  host->SetUserData(WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey,
+                    new base::UserDataAdapter<WebRtcLoggingHandlerHost>(
+                        webrtc_logging_handler_host));
+
+  AudioDebugRecordingsHandler* audio_debug_recordings_handler =
+      new AudioDebugRecordingsHandler(profile);
+  host->SetUserData(
+      AudioDebugRecordingsHandler::kAudioDebugRecordingsHandlerKey,
+      new base::UserDataAdapter<AudioDebugRecordingsHandler>(
+          audio_debug_recordings_handler));
+
+  WebRtcEventLogHandler* webrtc_event_log_handler =
+      new WebRtcEventLogHandler(profile);
+  host->SetUserData(WebRtcEventLogHandler::kWebRtcEventLogHandlerKey,
+                    new base::UserDataAdapter<WebRtcEventLogHandler>(
+                        webrtc_event_log_handler));
 #endif
 #if !defined(DISABLE_NACL)
   host->AddFilter(new nacl::NaClHostMessageFilter(
diff --git a/chrome/browser/chromeos/input_method/input_method_util.cc b/chrome/browser/chromeos/input_method/input_method_util.cc
index 11f39617..ba72137 100644
--- a/chrome/browser/chromeos/input_method/input_method_util.cc
+++ b/chrome/browser/chromeos/input_method/input_method_util.cc
@@ -10,6 +10,7 @@
 #include <functional>
 #include <map>
 #include <memory>
+#include <unordered_set>
 #include <utility>
 
 #include "base/macros.h"
@@ -687,9 +688,11 @@
   if (rewritten) {
     // Removes the duplicates.
     std::vector<std::string> new_ids;
+    std::unordered_set<std::string> ids_set;
     for (size_t i = 0; i < ids.size(); ++i) {
-      if (std::find(new_ids.begin(), new_ids.end(), ids[i]) == new_ids.end())
+      if (ids_set.find(ids[i]) == ids_set.end())
         new_ids.push_back(ids[i]);
+      ids_set.insert(ids[i]);
     }
     ids.swap(new_ids);
   }
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc
new file mode 100644
index 0000000..b621e23
--- /dev/null
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc
@@ -0,0 +1,265 @@
+// 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 "base/command_line.h"
+#include "base/json/json_writer.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/threading/platform_thread.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
+#include "chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h"
+#include "chrome/browser/extensions/extension_function_test_utils.h"
+#include "chrome/browser/extensions/extension_tab_util.h"
+#include "chrome/browser/media/webrtc_browsertest_base.h"
+#include "chrome/browser/media/webrtc_browsertest_common.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/test/browser_test_utils.h"
+#include "extensions/browser/api_test_utils.h"
+#include "extensions/common/test_util.h"
+#include "media/base/media_switches.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+
+#if defined(OS_WIN)
+#define IntToStringType base::IntToString16
+#else
+#define IntToStringType base::IntToString
+#endif
+
+using extensions::WebrtcLoggingPrivateStartWebRtcEventLoggingFunction;
+using extensions::WebrtcLoggingPrivateStopWebRtcEventLoggingFunction;
+
+namespace utils = extension_function_test_utils;
+
+namespace {
+
+// Get the expected EventLog file name. The name will be
+// <temporary path>.<render process id>.event_log.<consumer id>, for example
+// /tmp/.org.chromium.Chromium.vsygNQ/dnFW8ch/Default/WebRTC
+// Logs/WebRtcEventLog.1.29113.event_log.1
+base::FilePath GetExpectedEventLogFileName(const base::FilePath& base_file,
+                                           int render_process_id) {
+  static const int kExpectedConsumerId = 1;
+  return base_file.AddExtension(IntToStringType(render_process_id))
+      .AddExtension(FILE_PATH_LITERAL("event_log"))
+      .AddExtension(IntToStringType(kExpectedConsumerId));
+}
+
+static const char kMainWebrtcTestHtmlPage[] = "/webrtc/webrtc_jsep01_test.html";
+
+std::string ParamsToString(const base::ListValue& parameters) {
+  std::string parameter_string;
+  EXPECT_TRUE(base::JSONWriter::Write(parameters, &parameter_string));
+  return parameter_string;
+}
+
+class WebrtcEventLogApiTest : public WebRtcTestBase {
+ protected:
+  void SetUp() override {
+    WebRtcTestBase::SetUp();
+    extension_ = extensions::test_util::CreateEmptyExtension();
+  }
+
+  void SetUpInProcessBrowserTestFixture() override {
+    DetectErrorsInJavaScript();  // Look for errors in our rather complex js.
+  }
+
+  void SetUpCommandLine(base::CommandLine* command_line) override {
+    // Ensure the infobar is enabled, since we expect that in this test.
+    EXPECT_FALSE(command_line->HasSwitch(switches::kUseFakeUIForMediaStream));
+
+    // Always use fake devices.
+    command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
+
+    // Flag used by TestWebAudioMediaStream to force garbage collection.
+    command_line->AppendSwitchASCII(switches::kJavaScriptFlags, "--expose-gc");
+
+    // Enable the the event log in the extension API.
+    command_line->AppendSwitch(
+        switches::kEnableWebRtcEventLoggingFromExtension);
+  }
+
+  template <typename T>
+  scoped_refptr<T> CreateExtensionFunction() {
+    scoped_refptr<T> function(new T());
+    function->set_extension(extension_.get());
+    function->set_has_callback(true);
+    return function;
+  }
+
+  void AppendTabIdAndUrl(base::ListValue* parameters,
+                         content::WebContents* tab) {
+    base::DictionaryValue* request_info = new base::DictionaryValue();
+    request_info->SetInteger("tabId",
+                             extensions::ExtensionTabUtil::GetTabId(tab));
+    parameters->Append(request_info);
+    parameters->AppendString(tab->GetURL().GetOrigin().spec());
+  }
+
+ private:
+  scoped_refptr<extensions::Extension> extension_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(WebrtcEventLogApiTest, TestStartStopWebRtcEventLogging) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  content::WebContents* left_tab =
+      OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
+  content::WebContents* right_tab =
+      OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
+
+  SetupPeerconnectionWithLocalStream(left_tab);
+  SetupPeerconnectionWithLocalStream(right_tab);
+
+  NegotiateCall(left_tab, right_tab, "VP8");
+
+  StartDetectingVideo(left_tab, "remote-view");
+  StartDetectingVideo(right_tab, "remote-view");
+
+  // Start the event log.
+  const int seconds = 0;
+  base::ListValue start_params;
+  AppendTabIdAndUrl(&start_params, left_tab);
+  start_params.AppendInteger(seconds);
+  scoped_refptr<WebrtcLoggingPrivateStartWebRtcEventLoggingFunction>
+      start_function(CreateExtensionFunction<
+                     WebrtcLoggingPrivateStartWebRtcEventLoggingFunction>());
+  scoped_ptr<base::Value> start_result(utils::RunFunctionAndReturnSingleResult(
+      start_function.get(), ParamsToString(start_params), browser()));
+  ASSERT_TRUE(start_result.get());
+
+  // Get the file name.
+  scoped_ptr<extensions::api::webrtc_logging_private::RecordingInfo>
+      recordings_info_start(
+          extensions::api::webrtc_logging_private::RecordingInfo::FromValue(
+              *start_result.get()));
+  ASSERT_TRUE(recordings_info_start.get());
+  base::FilePath file_name_start(
+      base::FilePath::FromUTF8Unsafe(recordings_info_start->prefix_path));
+
+#if !defined(OS_MACOSX)
+  // Video is choppy on Mac OS X. http://crbug.com/443542.
+  WaitForVideoToPlay(left_tab);
+  WaitForVideoToPlay(right_tab);
+#endif
+
+  // Stop the event log.
+  base::ListValue stop_params;
+  AppendTabIdAndUrl(&stop_params, left_tab);
+  scoped_refptr<WebrtcLoggingPrivateStopWebRtcEventLoggingFunction>
+      stop_function(CreateExtensionFunction<
+                    WebrtcLoggingPrivateStopWebRtcEventLoggingFunction>());
+  scoped_ptr<base::Value> stop_result(utils::RunFunctionAndReturnSingleResult(
+      stop_function.get(), ParamsToString(stop_params), browser()));
+
+  // Get the file name.
+  scoped_ptr<extensions::api::webrtc_logging_private::RecordingInfo>
+      recordings_info_stop(
+          extensions::api::webrtc_logging_private::RecordingInfo::FromValue(
+              *stop_result.get()));
+  ASSERT_TRUE(recordings_info_stop.get());
+  base::FilePath file_name_stop(
+      base::FilePath::FromUTF8Unsafe(recordings_info_stop->prefix_path));
+
+  HangUp(left_tab);
+  HangUp(right_tab);
+
+  EXPECT_EQ(file_name_start, file_name_stop);
+
+  // Check that the file exists and is non-empty.
+  base::ProcessId render_process_id =
+      base::GetProcId(left_tab->GetRenderProcessHost()->GetHandle());
+  EXPECT_NE(render_process_id, base::kNullProcessId);
+  base::FilePath full_file_name =
+      GetExpectedEventLogFileName(file_name_stop, render_process_id);
+  int64_t file_size = 0;
+  while (!(base::PathExists(full_file_name) &&
+           base::GetFileSize(full_file_name, &file_size) && file_size > 0)) {
+    // This should normally not happen, but is here to prevent the test
+    // from becoming flaky on devices with weird timings or when the
+    // /webrtc/webrtc_jsep01_test.html changes.
+    VLOG(1) << "Waiting for logfile to become available...";
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  }
+  ASSERT_TRUE(base::PathExists(full_file_name));
+  EXPECT_TRUE(base::GetFileSize(full_file_name, &file_size));
+  EXPECT_GT(file_size, 0);
+
+  // Clean up.
+  base::DeleteFile(full_file_name, false);
+}
+
+IN_PROC_BROWSER_TEST_F(WebrtcEventLogApiTest,
+                       TestStartTimedWebRtcEventLogging) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+
+  content::WebContents* left_tab =
+      OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
+  content::WebContents* right_tab =
+      OpenTestPageAndGetUserMediaInNewTab(kMainWebrtcTestHtmlPage);
+
+  SetupPeerconnectionWithLocalStream(left_tab);
+  SetupPeerconnectionWithLocalStream(right_tab);
+
+  NegotiateCall(left_tab, right_tab, "VP8");
+
+  StartDetectingVideo(left_tab, "remote-view");
+  StartDetectingVideo(right_tab, "remote-view");
+
+  // Start the event log. RunFunctionAndReturnSingleResult will block until a
+  // result is available, which happens when the logging stops after 1 second.
+  const int seconds = 1;
+  base::ListValue start_params;
+  AppendTabIdAndUrl(&start_params, left_tab);
+  start_params.AppendInteger(seconds);
+  scoped_refptr<WebrtcLoggingPrivateStartWebRtcEventLoggingFunction>
+      start_function(CreateExtensionFunction<
+                     WebrtcLoggingPrivateStartWebRtcEventLoggingFunction>());
+  scoped_ptr<base::Value> start_result(utils::RunFunctionAndReturnSingleResult(
+      start_function.get(), ParamsToString(start_params), browser()));
+  ASSERT_TRUE(start_result.get());
+
+  // Get the file name.
+  scoped_ptr<extensions::api::webrtc_logging_private::RecordingInfo>
+      recordings_info_start(
+          extensions::api::webrtc_logging_private::RecordingInfo::FromValue(
+              *start_result.get()));
+  ASSERT_TRUE(recordings_info_start.get());
+  base::FilePath file_name_start(
+      base::FilePath::FromUTF8Unsafe(recordings_info_start->prefix_path));
+
+#if !defined(OS_MACOSX)
+  // Video is choppy on Mac OS X. http://crbug.com/443542.
+  WaitForVideoToPlay(left_tab);
+  WaitForVideoToPlay(right_tab);
+#endif
+
+  HangUp(left_tab);
+  HangUp(right_tab);
+
+  // The log has stopped automatically. Check that the file exists and is
+  // non-empty.
+  base::ProcessId render_process_id =
+      base::GetProcId(left_tab->GetRenderProcessHost()->GetHandle());
+  EXPECT_NE(render_process_id, base::kNullProcessId);
+  base::FilePath full_file_name =
+      GetExpectedEventLogFileName(file_name_start, render_process_id);
+  int64_t file_size = 0;
+  while (!(base::PathExists(full_file_name) &&
+           base::GetFileSize(full_file_name, &file_size) && file_size > 0)) {
+    // This should normally not happen, but is here to prevent the test
+    // from becoming flaky on devices with weird timings or when the
+    // /webrtc/webrtc_jsep01_test.html changes.
+    VLOG(1) << "Waiting for logfile to become available...";
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(100));
+  }
+  ASSERT_TRUE(base::PathExists(full_file_name));
+  EXPECT_TRUE(base::GetFileSize(full_file_name, &file_size));
+  EXPECT_GT(file_size, 0);
+
+  // Clean up.
+  base::DeleteFile(full_file_name, false);
+}
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
index 4d0ec4e9..291e7da 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc
@@ -42,6 +42,10 @@
     api::webrtc_logging_private::StartAudioDebugRecordings;
 namespace StopAudioDebugRecordings =
     api::webrtc_logging_private::StopAudioDebugRecordings;
+namespace StartWebRtcEventLogging =
+    api::webrtc_logging_private::StartWebRtcEventLogging;
+namespace StopWebRtcEventLogging =
+    api::webrtc_logging_private::StopWebRtcEventLogging;
 
 namespace {
 std::string HashIdWithOrigin(const std::string& security_origin,
@@ -96,7 +100,8 @@
   if (!host)
     return nullptr;
 
-  return base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host);
+  return base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
+      host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey);
 }
 
 scoped_refptr<WebRtcLoggingHandlerHost>
@@ -130,19 +135,19 @@
   SendResponse(success);
 }
 
-void WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback::
-    FireErrorCallback(const std::string& error_message) {
+void WebrtcLoggingPrivateFunctionWithRecordingDoneCallback::FireErrorCallback(
+    const std::string& error_message) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
   SetError(error_message);
   SendResponse(false);
 }
 
-void WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback::FireCallback(
+void WebrtcLoggingPrivateFunctionWithRecordingDoneCallback::FireCallback(
     const std::string& prefix_path,
     bool did_stop,
     bool did_manual_stop) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  api::webrtc_logging_private::AudioDebugRecordingsInfo result;
+  api::webrtc_logging_private::RecordingInfo result;
   result.prefix_path = prefix_path;
   result.did_stop = did_stop;
   result.did_manual_stop = did_manual_stop;
@@ -321,7 +326,8 @@
     return false;
 
   scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
+          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback = base::Bind(
       &WebrtcLoggingPrivateStartRtpDumpFunction::FireCallback, this);
@@ -364,7 +370,8 @@
     return false;
 
   scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(
+          host, WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey));
 
   WebRtcLoggingHandlerHost::GenericDoneCallback callback = base::Bind(
       &WebrtcLoggingPrivateStopRtpDumpFunction::FireCallback, this);
@@ -398,10 +405,11 @@
   if (!host)
     return false;
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+  scoped_refptr<AudioDebugRecordingsHandler> audio_debug_recordings_handler(
+      base::UserDataAdapter<AudioDebugRecordingsHandler>::Get(
+          host, AudioDebugRecordingsHandler::kAudioDebugRecordingsHandlerKey));
 
-  webrtc_logging_handler_host->StartAudioDebugRecordings(
+  audio_debug_recordings_handler->StartAudioDebugRecordings(
       host, base::TimeDelta::FromSeconds(params->seconds),
       base::Bind(
           &WebrtcLoggingPrivateStartAudioDebugRecordingsFunction::FireCallback,
@@ -427,10 +435,11 @@
   if (!host)
     return false;
 
-  scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host(
-      base::UserDataAdapter<WebRtcLoggingHandlerHost>::Get(host, host));
+  scoped_refptr<AudioDebugRecordingsHandler> audio_debug_recordings_handler(
+      base::UserDataAdapter<AudioDebugRecordingsHandler>::Get(
+          host, AudioDebugRecordingsHandler::kAudioDebugRecordingsHandlerKey));
 
-  webrtc_logging_handler_host->StopAudioDebugRecordings(
+  audio_debug_recordings_handler->StopAudioDebugRecordings(
       host,
       base::Bind(
           &WebrtcLoggingPrivateStopAudioDebugRecordingsFunction::FireCallback,
@@ -441,4 +450,69 @@
   return true;
 }
 
+bool WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::RunAsync() {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableWebRtcEventLoggingFromExtension)) {
+    return false;
+  }
+
+  scoped_ptr<StartWebRtcEventLogging::Params> params(
+      StartWebRtcEventLogging::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  if (params->seconds < 0) {
+    FireErrorCallback("seconds must be greater than or equal to 0");
+    return true;
+  }
+
+  content::RenderProcessHost* host =
+      RphFromRequest(params->request, params->security_origin);
+  if (!host)
+    return false;
+
+  scoped_refptr<WebRtcEventLogHandler> webrtc_event_log_handler(
+      base::UserDataAdapter<WebRtcEventLogHandler>::Get(
+          host, WebRtcEventLogHandler::kWebRtcEventLogHandlerKey));
+
+  webrtc_event_log_handler->StartWebRtcEventLogging(
+      host, base::TimeDelta::FromSeconds(params->seconds),
+      base::Bind(
+        &WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::FireCallback,
+        this),
+      base::Bind(
+        &WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::FireErrorCallback,
+        this));
+  return true;
+}
+
+bool WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::RunAsync() {
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableWebRtcEventLoggingFromExtension)) {
+    return false;
+  }
+
+  scoped_ptr<StopWebRtcEventLogging::Params> params(
+      StopWebRtcEventLogging::Params::Create(*args_));
+  EXTENSION_FUNCTION_VALIDATE(params.get());
+
+  content::RenderProcessHost* host =
+      RphFromRequest(params->request, params->security_origin);
+  if (!host)
+    return false;
+
+  scoped_refptr<WebRtcEventLogHandler> webrtc_event_log_handler(
+      base::UserDataAdapter<WebRtcEventLogHandler>::Get(
+          host, WebRtcEventLogHandler::kWebRtcEventLogHandlerKey));
+
+  webrtc_event_log_handler->StopWebRtcEventLogging(
+      host,
+      base::Bind(
+        &WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::FireCallback,
+        this),
+      base::Bind(
+        &WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::FireErrorCallback,
+        this));
+  return true;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
index ff5553b..4598a6e 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.h
@@ -9,6 +9,8 @@
 
 #include "chrome/browser/extensions/chrome_extension_function.h"
 #if defined(ENABLE_WEBRTC)
+#include "chrome/browser/media/audio_debug_recordings_handler.h"
+#include "chrome/browser/media/webrtc_event_log_handler.h"
 #include "chrome/browser/media/webrtc_logging_handler_host.h"
 #endif
 #include "chrome/common/extensions/api/webrtc_logging_private.h"
@@ -71,10 +73,10 @@
 #endif
 };
 
-class WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback
+class WebrtcLoggingPrivateFunctionWithRecordingDoneCallback
     : public WebrtcLoggingPrivateFunction {
  protected:
-  ~WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback() override {}
+  ~WebrtcLoggingPrivateFunctionWithRecordingDoneCallback() override {}
 
 #if defined(ENABLE_WEBRTC)
   // Must be called on UI thread.
@@ -226,7 +228,7 @@
 };
 
 class WebrtcLoggingPrivateStartAudioDebugRecordingsFunction
-    : public WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback {
+    : public WebrtcLoggingPrivateFunctionWithRecordingDoneCallback {
  public:
   DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.startAudioDebugRecordings",
                              WEBRTCLOGGINGPRIVATE_STARTAUDIODEBUGRECORDINGS)
@@ -240,7 +242,7 @@
 };
 
 class WebrtcLoggingPrivateStopAudioDebugRecordingsFunction
-    : public WebrtcLoggingPrivateFunctionWithAudioDebugRecordingsCallback {
+    : public WebrtcLoggingPrivateFunctionWithRecordingDoneCallback {
  public:
   DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.stopAudioDebugRecordings",
                              WEBRTCLOGGINGPRIVATE_STOPAUDIODEBUGRECORDINGS)
@@ -253,6 +255,34 @@
   bool RunAsync() override;
 };
 
+class WebrtcLoggingPrivateStartWebRtcEventLoggingFunction
+    : public WebrtcLoggingPrivateFunctionWithRecordingDoneCallback {
+ public:
+  DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.startWebRtcEventLogging",
+                             WEBRTCLOGGINGPRIVATE_STARTRTCEVENTLOGGING)
+  WebrtcLoggingPrivateStartWebRtcEventLoggingFunction() {}
+
+ private:
+  ~WebrtcLoggingPrivateStartWebRtcEventLoggingFunction() override {}
+
+  // ExtensionFunction overrides.
+  bool RunAsync() override;
+};
+
+class WebrtcLoggingPrivateStopWebRtcEventLoggingFunction
+    : public WebrtcLoggingPrivateFunctionWithRecordingDoneCallback {
+ public:
+  DECLARE_EXTENSION_FUNCTION("webrtcLoggingPrivate.stopWebRtcEventLogging",
+                             WEBRTCLOGGINGPRIVATE_STOPRTCEVENTLOGGING)
+  WebrtcLoggingPrivateStopWebRtcEventLoggingFunction() {}
+
+ private:
+  ~WebrtcLoggingPrivateStopWebRtcEventLoggingFunction() override {}
+
+  // ExtensionFunction overrides.
+  bool RunAsync() override;
+};
+
 }  // namespace extensions
 
 #endif  // CHROME_BROWSER_EXTENSIONS_API_WEBRTC_LOGGING_PRIVATE_WEBRTC_LOGGING_PRIVATE_API_H_
diff --git a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
index 256321ed..dd87afb 100644
--- a/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
+++ b/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api_stub.cc
@@ -86,4 +86,16 @@
   return false;
 }
 
+bool WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::RunAsync() {
+  SetError(kErrorNotSupported);
+  SendResponse(false);
+  return false;
+}
+
+bool WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::RunAsync() {
+  SetError(kErrorNotSupported);
+  SendResponse(false);
+  return false;
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/google/google_update_settings_posix.cc b/chrome/browser/google/google_update_settings_posix.cc
index a03d9ac..059672e 100644
--- a/chrome/browser/google/google_update_settings_posix.cc
+++ b/chrome/browser/google/google_update_settings_posix.cc
@@ -94,12 +94,13 @@
 
 // static
 // TODO(gab): Implement storing/loading for all ClientInfo fields on POSIX.
-scoped_ptr<metrics::ClientInfo> GoogleUpdateSettings::LoadMetricsClientInfo() {
-  scoped_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
+std::unique_ptr<metrics::ClientInfo>
+GoogleUpdateSettings::LoadMetricsClientInfo() {
+  std::unique_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
 
   base::AutoLock lock(g_posix_client_id_lock.Get());
   if (g_posix_client_id.Get().empty())
-    return scoped_ptr<metrics::ClientInfo>();
+    return nullptr;
   client_info->client_id = g_posix_client_id.Get();
 
   return client_info;
diff --git a/chrome/browser/media/audio_debug_recordings_handler.cc b/chrome/browser/media/audio_debug_recordings_handler.cc
new file mode 100644
index 0000000..7dae2865
--- /dev/null
+++ b/chrome/browser/media/audio_debug_recordings_handler.cc
@@ -0,0 +1,156 @@
+// 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 "chrome/browser/media/audio_debug_recordings_handler.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/media/webrtc_log_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+using content::BrowserThread;
+
+// Keys used to attach handler to the RenderProcessHost
+const char AudioDebugRecordingsHandler::kAudioDebugRecordingsHandlerKey[] =
+    "kAudioDebugRecordingsHandlerKey";
+
+namespace {
+
+// Returns a path name to be used as prefix for audio debug recordings files.
+base::FilePath GetAudioDebugRecordingsPrefixPath(
+    const base::FilePath& directory,
+    uint64_t audio_debug_recordings_id) {
+  static const char kAudioDebugRecordingsFilePrefix[] = "AudioDebugRecordings.";
+  return directory.AppendASCII(kAudioDebugRecordingsFilePrefix +
+                               base::Int64ToString(audio_debug_recordings_id));
+}
+
+}  // namespace
+
+AudioDebugRecordingsHandler::AudioDebugRecordingsHandler(Profile* profile)
+    : profile_(profile),
+      is_audio_debug_recordings_in_progress_(false),
+      current_audio_debug_recordings_id_(0) {
+  DCHECK(profile_);
+}
+
+AudioDebugRecordingsHandler::~AudioDebugRecordingsHandler() {}
+
+void AudioDebugRecordingsHandler::StartAudioDebugRecordings(
+    content::RenderProcessHost* host,
+    base::TimeDelta delay,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&AudioDebugRecordingsHandler::GetLogDirectoryAndEnsureExists,
+                 this),
+      base::Bind(&AudioDebugRecordingsHandler::DoStartAudioDebugRecordings,
+                 this, host, delay, callback, error_callback));
+}
+
+void AudioDebugRecordingsHandler::StopAudioDebugRecordings(
+    content::RenderProcessHost* host,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  const bool is_manual_stop = true;
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&AudioDebugRecordingsHandler::GetLogDirectoryAndEnsureExists,
+                 this),
+      base::Bind(&AudioDebugRecordingsHandler::DoStopAudioDebugRecordings, this,
+                 host, is_manual_stop, current_audio_debug_recordings_id_,
+                 callback, error_callback));
+}
+
+base::FilePath AudioDebugRecordingsHandler::GetLogDirectoryAndEnsureExists() {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::FilePath log_dir_path =
+      WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath());
+  base::File::Error error;
+  if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
+    DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
+    return base::FilePath();
+  }
+  return log_dir_path;
+}
+
+void AudioDebugRecordingsHandler::DoStartAudioDebugRecordings(
+    content::RenderProcessHost* host,
+    base::TimeDelta delay,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback,
+    const base::FilePath& log_directory) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (is_audio_debug_recordings_in_progress_) {
+    error_callback.Run("Audio debug recordings already in progress");
+    return;
+  }
+
+  is_audio_debug_recordings_in_progress_ = true;
+  base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
+      log_directory, ++current_audio_debug_recordings_id_);
+  host->EnableAudioDebugRecordings(prefix_path);
+
+  if (delay.is_zero()) {
+    const bool is_stopped = false, is_manual_stop = false;
+    callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+    return;
+  }
+
+  const bool is_manual_stop = false;
+  BrowserThread::PostDelayedTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&AudioDebugRecordingsHandler::DoStopAudioDebugRecordings, this,
+                 host, is_manual_stop, current_audio_debug_recordings_id_,
+                 callback, error_callback, log_directory),
+      delay);
+}
+
+void AudioDebugRecordingsHandler::DoStopAudioDebugRecordings(
+    content::RenderProcessHost* host,
+    bool is_manual_stop,
+    uint64_t audio_debug_recordings_id,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback,
+    const base::FilePath& log_directory) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_LE(audio_debug_recordings_id, current_audio_debug_recordings_id_);
+
+  base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
+      log_directory, audio_debug_recordings_id);
+  // Prevent an old posted StopAudioDebugRecordings() call to stop a newer dump.
+  // This could happen in a sequence like:
+  //   Start(10);  // Start dump 1. Post Stop() to run after 10 seconds.
+  //   Stop();     // Manually stop dump 1 before 10 seconds;
+  //   Start(20);  // Start dump 2. Posted Stop() for 1 should not stop dump 2.
+  if (audio_debug_recordings_id < current_audio_debug_recordings_id_) {
+    const bool is_stopped = false;
+    callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+    return;
+  }
+
+  if (!is_audio_debug_recordings_in_progress_) {
+    error_callback.Run("No audio debug recording in progress");
+    return;
+  }
+
+  host->DisableAudioDebugRecordings();
+  is_audio_debug_recordings_in_progress_ = false;
+  const bool is_stopped = true;
+  callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+}
diff --git a/chrome/browser/media/audio_debug_recordings_handler.h b/chrome/browser/media/audio_debug_recordings_handler.h
new file mode 100644
index 0000000..9511b6d
--- /dev/null
+++ b/chrome/browser/media/audio_debug_recordings_handler.h
@@ -0,0 +1,94 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_AUDIO_DEBUG_RECORDINGS_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_AUDIO_DEBUG_RECORDINGS_HANDLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+namespace content {
+class RenderProcessHost;
+}  // namespace content
+
+class Profile;
+
+// AudioDebugRecordingsHandler provides an interface to start and stop
+// AudioDebugRecordings, including WebRTC AEC dumps.
+class AudioDebugRecordingsHandler
+    : public base::RefCountedThreadSafe<AudioDebugRecordingsHandler> {
+ public:
+  typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
+  typedef base::Callback<void(const std::string&)> RecordingErrorCallback;
+  typedef base::Callback<void(const std::string&, bool, bool)>
+      RecordingDoneCallback;
+
+  // Key used to attach the handler to the RenderProcessHost
+  static const char kAudioDebugRecordingsHandlerKey[];
+
+  explicit AudioDebugRecordingsHandler(Profile* profile);
+
+  // Starts an audio debug recording. The recording lasts the given |delay|,
+  // unless |delay| is zero, in which case recording will continue until
+  // StopAudioDebugRecordings() is explicitly invoked.
+  // |callback| is invoked once recording stops. If |delay| is zero
+  // |callback| is invoked once recording starts.
+  // If a recording was already in progress, |error_callback| is invoked instead
+  // of |callback|.
+  void StartAudioDebugRecordings(content::RenderProcessHost* host,
+                                 base::TimeDelta delay,
+                                 const RecordingDoneCallback& callback,
+                                 const RecordingErrorCallback& error_callback);
+
+  // Stops an audio debug recording. |callback| is invoked once recording
+  // stops. If no recording was in progress, |error_callback| is invoked instead
+  // of |callback|.
+  void StopAudioDebugRecordings(content::RenderProcessHost* host,
+                                const RecordingDoneCallback& callback,
+                                const RecordingErrorCallback& error_callback);
+
+ private:
+  friend class base::RefCountedThreadSafe<AudioDebugRecordingsHandler>;
+
+  virtual ~AudioDebugRecordingsHandler();
+
+  base::FilePath GetLogDirectoryAndEnsureExists();
+
+  // Helper for starting audio debug recordings.
+  void DoStartAudioDebugRecordings(content::RenderProcessHost* host,
+                                   base::TimeDelta delay,
+                                   const RecordingDoneCallback& callback,
+                                   const RecordingErrorCallback& error_callback,
+                                   const base::FilePath& log_directory);
+
+  // Helper for stopping audio debug recordings.
+  void DoStopAudioDebugRecordings(content::RenderProcessHost* host,
+                                  bool is_manual_stop,
+                                  uint64_t audio_debug_recordings_id,
+                                  const RecordingDoneCallback& callback,
+                                  const RecordingErrorCallback& error_callback,
+                                  const base::FilePath& log_directory);
+
+  // The profile associated with our renderer process.
+  Profile* const profile_;
+
+  // Must be accessed on the UI thread.
+  bool is_audio_debug_recordings_in_progress_;
+
+  // This counter allows saving each debug recording in separate files.
+  uint64_t current_audio_debug_recordings_id_;
+
+  base::ThreadChecker thread_checker_;
+  DISALLOW_COPY_AND_ASSIGN(AudioDebugRecordingsHandler);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_AUDIO_DEBUG_RECORDINGS_HANDLER_H_
diff --git a/chrome/browser/media/webrtc_event_log_handler.cc b/chrome/browser/media/webrtc_event_log_handler.cc
new file mode 100644
index 0000000..0d9bacc
--- /dev/null
+++ b/chrome/browser/media/webrtc_event_log_handler.cc
@@ -0,0 +1,154 @@
+// 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 "chrome/browser/media/webrtc_event_log_handler.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_util.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "chrome/browser/media/webrtc_log_list.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_process_host.h"
+
+using content::BrowserThread;
+
+// Keys used to attach handler to the RenderProcessHost
+const char WebRtcEventLogHandler::kWebRtcEventLogHandlerKey[] =
+    "kWebRtcEventLogHandlerKey";
+
+namespace {
+
+// Returns a path name to be used as prefix for RTC event log files.
+base::FilePath GetWebRtcEventLogPrefixPath(const base::FilePath& directory,
+                                           uint64_t rtc_event_log_id) {
+  static const char kWebRtcEventLogFilePrefix[] = "WebRtcEventLog.";
+  return directory.AppendASCII(kWebRtcEventLogFilePrefix +
+                               base::Int64ToString(rtc_event_log_id));
+}
+
+}  // namespace
+
+WebRtcEventLogHandler::WebRtcEventLogHandler(Profile* profile)
+    : profile_(profile),
+      is_rtc_event_logging_in_progress_(false),
+      current_rtc_event_log_id_(0) {
+  DCHECK(profile_);
+  thread_checker_.DetachFromThread();
+}
+
+WebRtcEventLogHandler::~WebRtcEventLogHandler() {}
+
+void WebRtcEventLogHandler::StartWebRtcEventLogging(
+    content::RenderProcessHost* host,
+    base::TimeDelta delay,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&WebRtcEventLogHandler::GetLogDirectoryAndEnsureExists, this),
+      base::Bind(&WebRtcEventLogHandler::DoStartWebRtcEventLogging, this, host,
+                 delay, callback, error_callback));
+}
+
+void WebRtcEventLogHandler::StopWebRtcEventLogging(
+    content::RenderProcessHost* host,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  const bool is_manual_stop = true;
+  BrowserThread::PostTaskAndReplyWithResult(
+      BrowserThread::FILE, FROM_HERE,
+      base::Bind(&WebRtcEventLogHandler::GetLogDirectoryAndEnsureExists, this),
+      base::Bind(&WebRtcEventLogHandler::DoStopWebRtcEventLogging, this, host,
+                 is_manual_stop, current_rtc_event_log_id_, callback,
+                 error_callback));
+}
+
+base::FilePath WebRtcEventLogHandler::GetLogDirectoryAndEnsureExists() {
+  DCHECK_CURRENTLY_ON(BrowserThread::FILE);
+  base::FilePath log_dir_path =
+      WebRtcLogList::GetWebRtcLogDirectoryForProfile(profile_->GetPath());
+  base::File::Error error;
+  if (!base::CreateDirectoryAndGetError(log_dir_path, &error)) {
+    DLOG(ERROR) << "Could not create WebRTC log directory, error: " << error;
+    return base::FilePath();
+  }
+  return log_dir_path;
+}
+
+void WebRtcEventLogHandler::DoStartWebRtcEventLogging(
+    content::RenderProcessHost* host,
+    base::TimeDelta delay,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback,
+    const base::FilePath& log_directory) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+
+  if (is_rtc_event_logging_in_progress_) {
+    error_callback.Run("RTC event logging already in progress");
+    return;
+  }
+
+  is_rtc_event_logging_in_progress_ = true;
+  base::FilePath prefix_path =
+      GetWebRtcEventLogPrefixPath(log_directory, ++current_rtc_event_log_id_);
+  host->EnableEventLogRecordings(prefix_path);
+
+  if (delay.is_zero()) {
+    const bool is_stopped = false, is_manual_stop = false;
+    callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+    return;
+  }
+
+  const bool is_manual_stop = false;
+  BrowserThread::PostDelayedTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&WebRtcEventLogHandler::DoStopWebRtcEventLogging, this, host,
+                 is_manual_stop, current_rtc_event_log_id_, callback,
+                 error_callback, log_directory),
+      delay);
+}
+
+void WebRtcEventLogHandler::DoStopWebRtcEventLogging(
+    content::RenderProcessHost* host,
+    bool is_manual_stop,
+    uint64_t rtc_event_log_id,
+    const RecordingDoneCallback& callback,
+    const RecordingErrorCallback& error_callback,
+    const base::FilePath& log_directory) {
+  DCHECK(thread_checker_.CalledOnValidThread());
+  DCHECK_LE(rtc_event_log_id, current_rtc_event_log_id_);
+
+  base::FilePath prefix_path =
+      GetWebRtcEventLogPrefixPath(log_directory, rtc_event_log_id);
+  // Prevent an old posted DoStopWebRtcEventLogging() call to stop a newer dump.
+  // This could happen in a sequence like:
+  //   Start(10);  // Start dump 1. Post Stop() to run after 10 seconds.
+  //   Stop();     // Manually stop dump 1 before 10 seconds;
+  //   Start(20);  // Start dump 2. Posted Stop() for 1 should not stop dump 2.
+  if (rtc_event_log_id < current_rtc_event_log_id_) {
+    const bool is_stopped = false;
+    callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+    return;
+  }
+
+  if (!is_rtc_event_logging_in_progress_) {
+    error_callback.Run("No RTC event logging in progress");
+    return;
+  }
+
+  host->DisableEventLogRecordings();
+  is_rtc_event_logging_in_progress_ = false;
+  const bool is_stopped = true;
+  callback.Run(prefix_path.AsUTF8Unsafe(), is_stopped, is_manual_stop);
+}
diff --git a/chrome/browser/media/webrtc_event_log_handler.h b/chrome/browser/media/webrtc_event_log_handler.h
new file mode 100644
index 0000000..33eaa5c
--- /dev/null
+++ b/chrome/browser/media/webrtc_event_log_handler.h
@@ -0,0 +1,94 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEDIA_WEBRTC_EVENT_LOG_HANDLER_H_
+#define CHROME_BROWSER_MEDIA_WEBRTC_EVENT_LOG_HANDLER_H_
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/threading/thread_checker.h"
+#include "base/time/time.h"
+
+namespace content {
+class RenderProcessHost;
+}  // namespace content
+class Profile;
+
+// WebRtcEventLogHandler provides an interface to start and stop
+// the WebRTC event log.
+class WebRtcEventLogHandler
+    : public base::RefCountedThreadSafe<WebRtcEventLogHandler> {
+ public:
+  typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
+  typedef base::Callback<void(const std::string&)> RecordingErrorCallback;
+  typedef base::Callback<void(const std::string&, bool, bool)>
+      RecordingDoneCallback;
+
+  // Key used to attach the handler to the RenderProcessHost.
+  static const char kWebRtcEventLogHandlerKey[];
+
+  explicit WebRtcEventLogHandler(Profile* profile);
+
+  // Starts an RTC event log. The call writes the most recent events to a
+  // file and then starts logging events for the given |delay|.
+  // If |delay| is zero, the logging will continue until
+  // StopWebRtcEventLogging()
+  // is explicitly invoked.
+  // |callback| is invoked once recording stops. If |delay| is zero
+  // |callback| is invoked once recording starts.
+  // If a recording was already in progress, |error_callback| is invoked instead
+  // of |callback|.
+  void StartWebRtcEventLogging(content::RenderProcessHost* host,
+                               base::TimeDelta delay,
+                               const RecordingDoneCallback& callback,
+                               const RecordingErrorCallback& error_callback);
+
+  // Stops an RTC event log. |callback| is invoked once recording
+  // stops. If no recording was in progress, |error_callback| is invoked instead
+  // of |callback|.
+  void StopWebRtcEventLogging(content::RenderProcessHost* host,
+                              const RecordingDoneCallback& callback,
+                              const RecordingErrorCallback& error_callback);
+
+ private:
+  friend class base::RefCountedThreadSafe<WebRtcEventLogHandler>;
+  virtual ~WebRtcEventLogHandler();
+
+  base::FilePath GetLogDirectoryAndEnsureExists();
+
+  // Helper for starting RTC event logs.
+  void DoStartWebRtcEventLogging(content::RenderProcessHost* host,
+                                 base::TimeDelta delay,
+                                 const RecordingDoneCallback& callback,
+                                 const RecordingErrorCallback& error_callback,
+                                 const base::FilePath& log_directory);
+
+  // Helper for stopping RTC event logs.
+  void DoStopWebRtcEventLogging(content::RenderProcessHost* host,
+                                bool is_manual_stop,
+                                uint64_t audio_debug_recordings_id,
+                                const RecordingDoneCallback& callback,
+                                const RecordingErrorCallback& error_callback,
+                                const base::FilePath& log_directory);
+
+  // The profile associated with our renderer process.
+  Profile* const profile_;
+
+  // Must be accessed on the UI thread.
+  bool is_rtc_event_logging_in_progress_;
+
+  // This counter allows saving each log in a separate file.
+  uint64_t current_rtc_event_log_id_;
+
+  base::ThreadChecker thread_checker_;
+  DISALLOW_COPY_AND_ASSIGN(WebRtcEventLogHandler);
+};
+
+#endif  // CHROME_BROWSER_MEDIA_WEBRTC_EVENT_LOG_HANDLER_H_
diff --git a/chrome/browser/media/webrtc_logging_handler_host.cc b/chrome/browser/media/webrtc_logging_handler_host.cc
index 3e49559..d0549607 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.cc
+++ b/chrome/browser/media/webrtc_logging_handler_host.cc
@@ -52,6 +52,10 @@
 using base::IntToString;
 using content::BrowserThread;
 
+// Key used to attach the handler to the RenderProcessHost.
+const char WebRtcLoggingHandlerHost::kWebRtcLoggingHandlerHostKey[] =
+    "kWebRtcLoggingHandlerHostKey";
+
 namespace {
 
 const char kLogNotStoppedOrNoLogOpen[] =
@@ -103,15 +107,6 @@
   message->resize(message->size() - 1);
 }
 
-// Returns a path name to be used as prefix for audio debug recordings files.
-base::FilePath GetAudioDebugRecordingsPrefixPath(
-    const base::FilePath& directory,
-    uint64_t audio_debug_recordings_id) {
-  static const char kAudioDebugRecordingsFilePrefix[] = "AudioDebugRecordings.";
-  return directory.AppendASCII(kAudioDebugRecordingsFilePrefix +
-                               base::Int64ToString(audio_debug_recordings_id));
-}
-
 }  // namespace
 
 WebRtcLogBuffer::WebRtcLogBuffer()
@@ -156,8 +151,6 @@
       logging_state_(CLOSED),
       upload_log_on_render_close_(false),
       log_uploader_(log_uploader),
-      is_audio_debug_recordings_in_progress_(false),
-      current_audio_debug_recordings_id_(0),
       render_process_id_(render_process_id) {
   DCHECK(profile_);
   DCHECK(log_uploader_);
@@ -449,35 +442,6 @@
   }
 }
 
-void WebRtcLoggingHandlerHost::StartAudioDebugRecordings(
-    content::RenderProcessHost* host,
-    base::TimeDelta delay,
-    const AudioDebugRecordingsCallback& callback,
-    const AudioDebugRecordingsErrorCallback& error_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                 this),
-      base::Bind(&WebRtcLoggingHandlerHost::DoStartAudioDebugRecordings, this,
-                 host, delay, callback, error_callback));
-}
-
-void WebRtcLoggingHandlerHost::StopAudioDebugRecordings(
-    content::RenderProcessHost* host,
-    const AudioDebugRecordingsCallback& callback,
-    const AudioDebugRecordingsErrorCallback& error_callback) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  BrowserThread::PostTaskAndReplyWithResult(
-      BrowserThread::FILE, FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::GetLogDirectoryAndEnsureExists,
-                 this),
-      base::Bind(&WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings, this,
-                 host, true /* manual stop */,
-                 current_audio_debug_recordings_id_, callback, error_callback));
-}
-
 void WebRtcLoggingHandlerHost::OnChannelClosing() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   if (logging_state_ == STARTED || logging_state_ == STOPPED) {
@@ -841,69 +805,3 @@
       FROM_HERE,
       base::Bind(callback, success, error_message_with_state));
 }
-
-void WebRtcLoggingHandlerHost::DoStartAudioDebugRecordings(
-    content::RenderProcessHost* host,
-    base::TimeDelta delay,
-    const AudioDebugRecordingsCallback& callback,
-    const AudioDebugRecordingsErrorCallback& error_callback,
-    const base::FilePath& log_directory) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-  if (is_audio_debug_recordings_in_progress_) {
-    error_callback.Run("Audio debug recordings already in progress");
-    return;
-  }
-
-  is_audio_debug_recordings_in_progress_ = true;
-  base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
-      log_directory, ++current_audio_debug_recordings_id_);
-  host->EnableAudioDebugRecordings(prefix_path);
-
-  if (delay.is_zero()) {
-    callback.Run(prefix_path.AsUTF8Unsafe(), false /* not stopped */,
-                 false /* not manually stopped */);
-    return;
-  }
-
-  BrowserThread::PostDelayedTask(
-      BrowserThread::UI, FROM_HERE,
-      base::Bind(&WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings, this,
-                 host, false /* no manual stop */,
-                 current_audio_debug_recordings_id_, callback, error_callback,
-                 prefix_path),
-      delay);
-}
-
-void WebRtcLoggingHandlerHost::DoStopAudioDebugRecordings(
-    content::RenderProcessHost* host,
-    bool is_manual_stop,
-    uint64_t audio_debug_recordings_id,
-    const AudioDebugRecordingsCallback& callback,
-    const AudioDebugRecordingsErrorCallback& error_callback,
-    const base::FilePath& log_directory) {
-  DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  DCHECK_LE(audio_debug_recordings_id, current_audio_debug_recordings_id_);
-
-  base::FilePath prefix_path = GetAudioDebugRecordingsPrefixPath(
-      log_directory, audio_debug_recordings_id);
-  // Prevent an old posted StopAudioDebugRecordings() call to stop a newer dump.
-  // This could happen in a sequence like:
-  //   Start(10);  //Start dump 1. Post Stop() to run after 10 seconds.
-  //   Stop();  // Manually stop dump 1 before 10 seconds;
-  //   Start(20);  // Start dump 2. Posted Stop() for 1 should not stop dump 2.
-  if (audio_debug_recordings_id < current_audio_debug_recordings_id_) {
-    callback.Run(prefix_path.AsUTF8Unsafe(), false /* not stopped */,
-                 is_manual_stop);
-    return;
-  }
-
-  if (!is_audio_debug_recordings_in_progress_) {
-    error_callback.Run("No audio debug recording in progress");
-    return;
-  }
-
-  host->DisableAudioDebugRecordings();
-  is_audio_debug_recordings_in_progress_ = false;
-  callback.Run(prefix_path.AsUTF8Unsafe(), true /* stopped */, is_manual_stop);
-}
diff --git a/chrome/browser/media/webrtc_logging_handler_host.h b/chrome/browser/media/webrtc_logging_handler_host.h
index 66ddd4ab..f55ee84 100644
--- a/chrome/browser/media/webrtc_logging_handler_host.h
+++ b/chrome/browser/media/webrtc_logging_handler_host.h
@@ -8,6 +8,10 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <map>
+#include <string>
+#include <vector>
+
 #include "base/macros.h"
 #include "base/memory/shared_memory.h"
 #include "build/build_config.h"
@@ -81,10 +85,9 @@
   typedef base::Callback<void(bool, const std::string&)> GenericDoneCallback;
   typedef base::Callback<void(bool, const std::string&, const std::string&)>
       UploadDoneCallback;
-  typedef base::Callback<void(const std::string&)>
-      AudioDebugRecordingsErrorCallback;
-  typedef base::Callback<void(const std::string&, bool, bool)>
-      AudioDebugRecordingsCallback;
+
+  // Key used to attach the handler to the RenderProcessHost.
+  static const char kWebRtcLoggingHandlerHostKey[];
 
   WebRtcLoggingHandlerHost(int render_process_id,
                            Profile* profile,
@@ -156,27 +159,6 @@
                    size_t packet_length,
                    bool incoming);
 
-  // Starts an audio debug recording. The recording lasts the given |delay|,
-  // unless |delay| is zero, in which case recording will continue until
-  // StopAudioDebugRecordings() is explicitly invoked.
-  // |callback| is invoked once recording stops. If |delay| is zero
-  // |callback| is invoked once recording starts.
-  // If a recording was already in progress, |error_callback| is invoked instead
-  // of |callback|.
-  void StartAudioDebugRecordings(
-      content::RenderProcessHost* host,
-      base::TimeDelta delay,
-      const AudioDebugRecordingsCallback& callback,
-      const AudioDebugRecordingsErrorCallback& error_callback);
-
-  // Stops an audio debug recording. |callback| is invoked once recording
-  // stops. If no recording was in progress, |error_callback| is invoked instead
-  // of |callback|.
-  void StopAudioDebugRecordings(
-      content::RenderProcessHost* host,
-      const AudioDebugRecordingsCallback& callback,
-      const AudioDebugRecordingsErrorCallback& error_callback);
-
  private:
   // States used for protecting from function calls made at non-allowed points
   // in time. For example, StartLogging() is only allowed in CLOSED state.
@@ -266,23 +248,6 @@
       bool success,
       const std::string& error_message);
 
-  // Helper for starting audio debug recordings.
-  void DoStartAudioDebugRecordings(
-      content::RenderProcessHost* host,
-      base::TimeDelta delay,
-      const AudioDebugRecordingsCallback& callback,
-      const AudioDebugRecordingsErrorCallback& error_callback,
-      const base::FilePath& log_directory);
-
-  // Helper for stopping audio debug recordings.
-  void DoStopAudioDebugRecordings(
-      content::RenderProcessHost* host,
-      bool is_manual_stop,
-      uint64_t audio_debug_recordings_id,
-      const AudioDebugRecordingsCallback& callback,
-      const AudioDebugRecordingsErrorCallback& error_callback,
-      const base::FilePath& log_directory);
-
   std::unique_ptr<WebRtcLogBuffer> log_buffer_;
 
   // The profile associated with our renderer process.
@@ -324,12 +289,6 @@
   // Ownership lies with the browser process.
   WebRtcLogUploader* const log_uploader_;
 
-  // Must be accessed on the UI thread.
-  bool is_audio_debug_recordings_in_progress_;
-
-  // This counter allows saving each debug recording in separate files.
-  uint64_t current_audio_debug_recordings_id_;
-
   // The render process ID this object belongs to.
   int render_process_id_;
 
diff --git a/chrome/browser/process_singleton_win.cc b/chrome/browser/process_singleton_win.cc
index 3352156..45d98416 100644
--- a/chrome/browser/process_singleton_win.cc
+++ b/chrome/browser/process_singleton_win.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/process_singleton.h"
 
+#include <windows.h>
 #include <shellapi.h>
 #include <stddef.h>
 
@@ -12,6 +13,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
+#include "base/path_service.h"
 #include "base/process/process.h"
 #include "base/process/process_info.h"
 #include "base/strings/string_number_conversions.h"
@@ -26,17 +28,27 @@
 #include "chrome/browser/chrome_process_finder_win.h"
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/ui/simple_message_box.h"
+#include "chrome/common/channel_info.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/chrome_paths_internal.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/grit/chromium_strings.h"
+#include "chrome/installer/util/google_update_settings.h"
+#include "chrome/installer/util/util_constants.h"
 #include "chrome/installer/util/wmi.h"
+#include "components/version_info/version_info.h"
 #include "content/public/common/result_codes.h"
 #include "net/base/escape.h"
+#include "third_party/kasko/kasko_features.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/win/hwnd_util.h"
 
+#if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+#include "chrome/app/chrome_crash_reporter_client.h"
+#include "chrome/chrome_watcher/kasko_util.h"
+#endif  // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+
 namespace {
 
 const char kLockfile[] = "lockfile";
@@ -179,6 +191,69 @@
          chrome::MESSAGE_BOX_RESULT_NO;
 }
 
+#if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+// Capture a failed rendez-vous hang report of the other process. Kasko needs
+// the exception context to live either in the dumper or the dumpee. This
+// means we cannot rely on kasko reporters from either browser watcher, and
+// instead spin up a new reporter.
+void SendFailedRdvReport(const base::Process& process, DWORD thread_id) {
+  // Check whether reports can be uploaded. This involves checking group policy,
+  // stats collection consent and whether running on a bot. The correct approach
+  // would be to rely on crash_reporter::GetUploadsEnabled(). However, on
+  // Windows, the crash client is only expected to be linked into chrome.exe
+  // (not the dlls). That means CrashPad globals are not set and we cannot call
+  // crash_reporter::GetUploadsEnabled(). As a temporary measure until Kasko is
+  // no longer used, we duplicate CrashPad's logic here.
+  ChromeCrashReporterClient crash_reporter_client;
+
+  bool enable_uploads = false;
+  if (!crash_reporter_client.ReportingIsEnforcedByPolicy(&enable_uploads)) {
+    // Breakpad provided a --disable-breakpad switch to disable crash dumping
+    // (not just uploading) here. Crashpad doesn't need it: dumping is enabled
+    // unconditionally and uploading is gated on consent, which tests/bots
+    // shouldn't have. As a precaution, uploading is also disabled on bots
+    // even if consent is present.
+    enable_uploads = crash_reporter_client.GetCollectStatsConsent() &&
+                     !crash_reporter_client.IsRunningUnattended();
+  }
+
+  if (!enable_uploads)
+    return;
+
+  // TODO(manzagop): add a metric for the number of captured hang reports, for
+  //   comparison with uploaded count?
+
+  // Only report on canary (or unspecified).
+  const version_info::Channel channel = chrome::GetChannel();
+  if (channel != version_info::Channel::UNKNOWN &&
+      channel != version_info::Channel::CANARY) {
+    return;
+  }
+  // TODO(manzagop): add a metric for the number of times this does not match.
+  if (!EnsureTargetProcessValidForCapture(process))
+    return;
+
+  // Initialize a reporter, capture a report and shutdown the reporter.
+  base::FilePath watcher_data_directory;
+  if (PathService::Get(chrome::DIR_WATCHER_DATA, &watcher_data_directory)) {
+    base::string16 endpoint =
+        L"chrome_kasko_rdv_" +
+        base::UintToString16(base::Process::Current().Pid());
+
+    bool launched_kasko = InitializeKaskoReporter(
+        endpoint, watcher_data_directory.value().c_str());
+    if (launched_kasko) {
+      DumpHungProcess(thread_id, installer::kChromeChannelCanary, L"failed-rdv",
+                      process);
+      // We immediately request Kasko shutdown. This may block until the
+      // completion of ongoing background tasks (e.g., upload). If the report is
+      // not uploaded by this reporter, any other Kasko reporter may upload it.
+      ShutdownKaskoReporter();
+    }
+  }
+}
+#endif  // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+
 }  // namespace
 
 // Microsoft's Softricity virtualization breaks the sandbox processes.
@@ -249,15 +324,27 @@
       break;
   }
 
+  // The window is hung.
   DWORD process_id = 0;
   DWORD thread_id = ::GetWindowThreadProcessId(remote_window_, &process_id);
   if (!thread_id || !process_id) {
     remote_window_ = NULL;
     return PROCESS_NONE;
   }
+
+  // Get a handle to the process that created the window.
   base::Process process = base::Process::Open(process_id);
 
-  // The window is hung. Scan for every window to find a visible one.
+  // Optionally send a failed rendez-vous report.
+  // Note: we nominate the thread that created the window as the root of the
+  // search for a hung thread.
+#if defined(GOOGLE_CHROME_BUILD)
+#if BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+  SendFailedRdvReport(process, thread_id);
+#endif  // BUILDFLAG(ENABLE_KASKO_FAILED_RDV_REPORTS)
+#endif  // GOOGLE_CHROME_BUILD
+
+  // Scan for every window to find a visible one.
   bool visible_window = false;
   ::EnumThreadWindows(thread_id,
                       &BrowserWindowEnumeration,
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay_data.js b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
index c3489d6..be046e0 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay_data.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
@@ -15784,6 +15784,7 @@
     '0<>CTRL': 'keyboardOverlayResetZoom',
     '0<>CTRL<>SHIFT': 'keyboardOverlayResetScreenZoom',
     '0<>SEARCH': 'keyboardOverlayF10',
+    '0<>SEARCH<>SHIFT': 'keyboardOverlayContextMenu',
     '1<>ALT': 'keyboardOverlayActivateShelfItem1',
     '1<>CTRL': 'keyboardOverlayActivateTab1',
     '1<>SEARCH': 'keyboardOverlayF1',
@@ -15914,6 +15915,7 @@
     'v<>CTRL<>SHIFT': 'keyboardOverlayPasteAsPlainText',
     'vol. down<>SEARCH': 'keyboardOverlayF9',
     'vol. up<>SEARCH': 'keyboardOverlayF10',
+    'vol. up<>SEARCH<>SHIFT': 'keyboardOverlayContextMenu',
     'w<>CTRL': 'keyboardOverlayCloseTab',
     'w<>CTRL<>SHIFT': 'keyboardOverlayCloseWindow',
     'x<>CTRL': 'keyboardOverlayCut',
diff --git a/chrome/browser/resources/hangout_services/manifest.json b/chrome/browser/resources/hangout_services/manifest.json
index 92255eb..f495820 100644
--- a/chrome/browser/resources/hangout_services/manifest.json
+++ b/chrome/browser/resources/hangout_services/manifest.json
@@ -5,7 +5,7 @@
   "name": "Google Hangouts",
   // Note: Always update the version number when this file is updated. Chrome
   // triggers extension preferences update on the version increase.
-  "version": "1.2.0",
+  "version": "1.3.0",
   "manifest_version": 2,
   "externally_connectable": {
     "matches": [
diff --git a/chrome/browser/resources/hangout_services/thunk.js b/chrome/browser/resources/hangout_services/thunk.js
index db15006..ef44a26 100644
--- a/chrome/browser/resources/hangout_services/thunk.js
+++ b/chrome/browser/resources/hangout_services/thunk.js
@@ -172,7 +172,17 @@
           chrome.webrtcLoggingPrivate.stopAudioDebugRecordings(
               requestInfo, origin, doSendResponse);
           return true;
+        } else if (method == 'logging.startWebRtcEventLogging') {
+          var seconds = message['seconds'] || 0;
+          chrome.webrtcLoggingPrivate.startWebRtcEventLogging(
+              requestInfo, origin, seconds, doSendResponse);
+          return true;
+        } else if (method == 'logging.stopWebRtcEventLogging') {
+          chrome.webrtcLoggingPrivate.stopWebRtcEventLogging(
+              requestInfo, origin, doSendResponse);
+          return true;
         }
+
         throw new Error('Unknown method: ' + method);
       } catch (e) {
         doSendResponse(null, e.name + ': ' + e.message);
diff --git a/chrome/browser/resources/net_internals/index.html b/chrome/browser/resources/net_internals/index.html
index 00b350f1..309e9af1 100644
--- a/chrome/browser/resources/net_internals/index.html
+++ b/chrome/browser/resources/net_internals/index.html
@@ -1,4 +1,4 @@
-<!DOCTYPE HTML>
+<!DOCTYPE HTML>
 <html>
 <!--
 Copyright (c) 2012 The Chromium Authors. All rights reserved.
@@ -25,6 +25,9 @@
   <body id=import-view-drop-target>
     <include src="top_bar_view.html">
 
+    <div id="tab-list">
+    </div>
+
     <div id=main-tab-contents>
       <include src="proxy_view.html">
       <include src="dns_view.html">
diff --git a/chrome/browser/resources/net_internals/log_util.js b/chrome/browser/resources/net_internals/log_util.js
index 2ca415e0..54a0607 100644
--- a/chrome/browser/resources/net_internals/log_util.js
+++ b/chrome/browser/resources/net_internals/log_util.js
@@ -259,7 +259,7 @@
         errorString += 'Caught error while calling onLoadLogFinish: ' +
                        error + '\n\n';
       }
-      tabSwitcher.showMenuItem(tabId, showView);
+      tabSwitcher.showTabLink(tabId, showView);
     }
 
     return errorString + 'Log loaded.';
diff --git a/chrome/browser/resources/net_internals/main.css b/chrome/browser/resources/net_internals/main.css
index b8a005c..a96a7f1a 100644
--- a/chrome/browser/resources/net_internals/main.css
+++ b/chrome/browser/resources/net_internals/main.css
@@ -76,6 +76,34 @@
   padding-right: 4px;
 }
 
+#tab-list {
+  border-right: 1px solid rgb(170,170,170);
+  display: inline-block;
+  overflow-x: hidden;
+  overflow-y: auto;
+  padding: 0;
+}
+
+#tab-list a {
+  display: inline-block;
+  font-size: 16px;
+  margin: 0;
+  padding: 2px 10px;
+  text-decoration: none;
+  white-space: nowrap;
+  width: 100%;
+}
+
+#tab-list a,
+#tab-list a:visited {
+  color: rgb(140,140,140);
+}
+
+#tab-list .selected,
+#tab-list a:hover {
+  color: black;
+}
+
 .styled-table th {
   background: rgb(224,236,255);
 }
diff --git a/chrome/browser/resources/net_internals/main.js b/chrome/browser/resources/net_internals/main.js
index 0034a981..33d6293 100644
--- a/chrome/browser/resources/net_internals/main.js
+++ b/chrome/browser/resources/net_internals/main.js
@@ -155,9 +155,7 @@
       this.tabIdToHash_ = {};
       this.hashToTabId_ = {};
 
-      this.tabSwitcher_ = new TabSwitcherView(
-          $(TopBarView.TAB_DROPDOWN_MENU_ID),
-          this.onTabSwitched_.bind(this));
+      this.tabSwitcher_ = new TabSwitcherView(this.onTabSwitched_.bind(this));
 
       // Helper function to add a tab given the class for a view singleton.
       var addTab = function(viewClass) {
@@ -174,7 +172,7 @@
           throw Error('Tab hashes must start with a #');
         }
 
-        this.tabSwitcher_.addTab(tabId, view, tabName);
+        this.tabSwitcher_.addTab(tabId, view, tabName, tabHash);
         this.tabIdToHash_[tabId] = tabHash;
         this.hashToTabId_[tabHash] = tabId;
       }.bind(this);
@@ -201,7 +199,7 @@
       addTab(PrerenderView);
       addTab(CrosView);
 
-      this.tabSwitcher_.showMenuItem(CrosView.TAB_ID, cr.isChromeOS);
+      this.tabSwitcher_.showTabLink(CrosView.TAB_ID, cr.isChromeOS);
     },
 
     /**
diff --git a/chrome/browser/resources/net_internals/status_view.html b/chrome/browser/resources/net_internals/status_view.html
index 021b103..ba28840 100644
--- a/chrome/browser/resources/net_internals/status_view.html
+++ b/chrome/browser/resources/net_internals/status_view.html
@@ -5,7 +5,7 @@
 -->
 
 <!-- Status bar at top of screen when in capture mode. -->
-<div id=capture-status-view style="display:none">
+<div id=capture-status-view>
   <span style='-webkit-flex-grow: 1'>
     <a href='#capture' class=capture-status-view-link>capturing</a>
     <a href='#events' class=capture-status-view-link>events
diff --git a/chrome/browser/resources/net_internals/tab_switcher_view.js b/chrome/browser/resources/net_internals/tab_switcher_view.js
index 9abdc87..fadc3d7 100644
--- a/chrome/browser/resources/net_internals/tab_switcher_view.js
+++ b/chrome/browser/resources/net_internals/tab_switcher_view.js
@@ -17,27 +17,31 @@
   // We inherit from View.
   var superClass = View;
 
+  var TAB_LIST_ID = 'tab-list';
+
   /**
    * @constructor
    *
-   * @param {DOMSelectNode} dropdownMenu The menu for switching between tabs.
-   *                        The TabSwitcherView will attach an onchange event to
-   *                        the dropdown menu, and control the selected index.
    * @param {?Function} opt_onTabSwitched Optional callback to run when the
    *                    active tab changes. Called as
    *                    opt_onTabSwitched(oldTabId, newTabId).
    */
-  function TabSwitcherView(dropdownMenu, opt_onTabSwitched) {
+  function TabSwitcherView(opt_onTabSwitched) {
     assertFirstConstructorCall(TabSwitcherView);
 
     this.tabIdToView_ = {};
+    this.tabIdToLink_ = {};
+    // Ordered list of views.
+    this.viewList_ = [];
     this.activeTabId_ = null;
 
-    this.dropdownMenu_ = dropdownMenu;
-    this.dropdownMenu_.onchange = this.onMenuSelectionChanged_.bind(this);
-
     this.onTabSwitched_ = opt_onTabSwitched;
 
+    // The ideal width of the tab list.  If width is reduced below this, the
+    // tab list will be shrunk, but it will be returned to this width once it
+    // can be.
+    this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
+
     superClass.call(this);
   }
 
@@ -52,10 +56,22 @@
     setGeometry: function(left, top, width, height) {
       superClass.prototype.setGeometry.call(this, left, top, width, height);
 
-      // Position each of the tabs content areas.
+      var tabListNode = $(TAB_LIST_ID);
+
+      // Set position of the tab list.  Can't use DivView because DivView sets
+      // a fixed width at creation time, and need to set the width of the tab
+      // list only after its been populated.
+      var tabListWidth = this.tabListWidth_;
+      if (tabListWidth > width)
+        tabListWidth = width;
+      tabListNode.style.position = 'absolute';
+      setNodePosition(tabListNode, left, top, tabListWidth, height);
+
+      // Position each of the tab's content areas.
       for (var tabId in this.tabIdToView_) {
         var view = this.tabIdToView_[tabId];
-        view.setGeometry(left, top, width, height);
+        view.setGeometry(left + tabListWidth, top, width - tabListWidth,
+                         height);
       }
     },
 
@@ -69,46 +85,43 @@
     // ---------------------------------------------
 
     /**
-     * Adds a new tab (initially hidden).
+     * Adds a new tab (initially hidden).  To ensure correct tab list sizing,
+     * may only be called before first layout.
      *
      * @param {string} tabId The ID to refer to the tab by.
      * @param {!View} view The tab's actual contents.
      * @param {string} name The name for the menu item that selects the tab.
      */
-    addTab: function(tabId, view, name) {
+    addTab: function(tabId, view, name, hash) {
       if (!tabId) {
         throw Error('Must specify a non-false tabId');
       }
 
       this.tabIdToView_[tabId] = view;
+      this.viewList_.push(view);
+
+      var node = addNodeWithText($(TAB_LIST_ID), 'a', name);
+      node.href = hash;
+      this.tabIdToLink_[tabId] = node;
+      addNode($(TAB_LIST_ID), 'br');
 
       // Tab content views start off hidden.
       view.show(false);
 
-      // Add it to the dropdown menu.
-      var menuItem = addNode(this.dropdownMenu_, 'option');
-      menuItem.value = tabId;
-      menuItem.textContent = name;
+      this.tabListWidth_ = $(TAB_LIST_ID).offsetWidth;
     },
 
-    showMenuItem: function(tabId, isVisible) {
+    showTabLink: function(tabId, isVisible) {
       var wasActive = this.activeTabId_ == tabId;
 
-      // Hide the menuitem from the list. Note it needs to be 'disabled' to
-      // prevent it being selectable from keyboard.
-      var menuitem = this.getMenuItemNode_(tabId);
-      setNodeDisplay(menuitem, isVisible);
-      menuitem.disabled = !isVisible;
+      setNodeDisplay(this.tabIdToLink_[tabId], isVisible);
 
       if (wasActive && !isVisible) {
-        // If the active tab is being hidden in the dropdown menu, then
-        // switch to the first tab which is still visible.
-        for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
-          var option = this.dropdownMenu_.options[i];
-          if (option.style.display != 'none') {
+        // If the link for active tab is being hidden, then switch to the first
+        // tab which is still visible.
+        for (var view in this.viewList_) {
+          if (view.isVisible())
             this.switchToTab(option.value);
-            break;
-          }
         }
       }
     },
@@ -145,32 +158,19 @@
       var oldTabId = this.activeTabId_;
       this.activeTabId_ = tabId;
 
-      this.dropdownMenu_.value = tabId;
-
-      // Hide the previously visible tab contents.
-      if (oldTabId)
+      if (oldTabId) {
+        this.tabIdToLink_[oldTabId].classList.remove('selected');
+        // Hide the previously visible tab contents.
         this.getTabView(oldTabId).show(false);
+      }
+
+      this.tabIdToLink_[tabId].classList.add('selected');
 
       newView.show(this.isVisible());
 
       if (this.onTabSwitched_)
         this.onTabSwitched_(oldTabId, tabId);
     },
-
-    getMenuItemNode_: function(tabId) {
-      for (var i = 0; i < this.dropdownMenu_.options.length; ++i) {
-        var option = this.dropdownMenu_.options[i];
-        if (option.value == tabId) {
-          return option;
-        }
-      }
-      return null;
-    },
-
-    onMenuSelectionChanged_: function(event) {
-      var tabId = this.dropdownMenu_.value;
-      this.switchToTab(tabId);
-    },
   };
 
   return TabSwitcherView;
diff --git a/chrome/browser/resources/net_internals/top_bar_view.html b/chrome/browser/resources/net_internals/top_bar_view.html
index 35e9a08..5698ad7 100644
--- a/chrome/browser/resources/net_internals/top_bar_view.html
+++ b/chrome/browser/resources/net_internals/top_bar_view.html
@@ -8,43 +8,6 @@
 
 <style>
 
-/**
- * This SELECT dropdown is styled so the dropdown arrow is hidden. This is
- * necessary because it looks bad on Windows. Instead, an arrow is added
- * manually by overlaying U+25BC over the dropdown and making it un-clickable.
- **/
-#top-bar-view-tab-selecter {
-  -webkit-appearance: none;
-  background: white;
-  border-radius: 6px;
-  border: 1px solid #aaa;
-  font-size: 13px;
-  height: 25px;
-  outline: none;
-  padding: 0 18px 2px 0.5em;
-}
-
-.top-bar-view-arrow {
-  display: inline-block;
-  margin-right: 10px;
-  position:relative;
-}
-
-.top-bar-view-arrow::after {
-  color: black;
-  content: '\25bc';
-  font-size: 9px;
-  line-height: 23px;
-  pointer-events: none;
-  position: absolute;
-  right: 12px;
-  top: 1px;
-}
-
-#top-bar-view-tab-selecter:focus {
-  box-shadow: 0 0 3px 4px rgba(255, 238, 0, 0.50);
-}
-
 #top-bar-view {
   -webkit-align-items: center;
   border-bottom: 1px solid gray;
@@ -55,9 +18,6 @@
 </style>
 
 <div id=top-bar-view>
-  <span class=top-bar-view-arrow>
-    <select aria-label="Tab selector" id=top-bar-view-tab-selecter></select>
-  </span>
   <div style="-webkit-flex-grow: 1">
     <include src="status_view.html">
   </div>
diff --git a/chrome/browser/resources/net_internals/top_bar_view.js b/chrome/browser/resources/net_internals/top_bar_view.js
index 6eb503a..095417b 100644
--- a/chrome/browser/resources/net_internals/top_bar_view.js
+++ b/chrome/browser/resources/net_internals/top_bar_view.js
@@ -32,7 +32,6 @@
   }
 
   TopBarView.BOX_ID = 'top-bar-view';
-  TopBarView.TAB_DROPDOWN_MENU_ID = 'top-bar-view-tab-selecter';
 
   cr.addSingletonGetter(TopBarView);
 
diff --git a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
index 9a6cad0..8635cd8 100644
--- a/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_context_menu.cc
@@ -202,7 +202,7 @@
     case MENU_AUTO_HIDE:
     case MENU_ALIGNMENT_MENU:
     case MENU_CHANGE_WALLPAPER:
-      ExecuteCommand(command_id, event_flags);
+      LauncherContextMenu::ExecuteCommand(command_id, event_flags);
       return true;
     default:
       return false;
diff --git a/chrome/browser/ui/find_bar/find_tab_helper.cc b/chrome/browser/ui/find_bar/find_tab_helper.cc
index 92b64a2d..c9465021 100644
--- a/chrome/browser/ui/find_bar/find_tab_helper.cc
+++ b/chrome/browser/ui/find_bar/find_tab_helper.cc
@@ -77,8 +77,8 @@
   bool find_next = (find_text_ == search_string || search_string.empty()) &&
                    (last_search_case_sensitive_ == case_sensitive) &&
                    !find_op_aborted_;
-  if (!find_next)
-    current_find_request_id_ = find_request_id_counter_++;
+
+  current_find_request_id_ = find_request_id_counter_++;
 
   if (!search_string.empty())
     find_text_ = search_string;
@@ -141,14 +141,13 @@
 #if defined(OS_ANDROID)
 void FindTabHelper::ActivateNearestFindResult(float x, float y) {
   if (!find_op_aborted_ && !find_text_.empty()) {
-    web_contents()->GetMainFrame()->ActivateNearestFindResult(
-        current_find_request_id_, x, y);
+    web_contents()->ActivateNearestFindResult(x, y);
   }
 }
 
 void FindTabHelper::RequestFindMatchRects(int current_version) {
   if (!find_op_aborted_ && !find_text_.empty())
-    web_contents()->GetMainFrame()->RequestFindMatchRects(current_version);
+    web_contents()->RequestFindMatchRects(current_version);
 }
 #endif
 
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index c7658e53..e07ee50 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -135,6 +135,7 @@
     IDS_KEYBOARD_OVERLAY_CLEAR_BROWSING_DATA_DIALOG },
   { "keyboardOverlayCloseTab", IDS_KEYBOARD_OVERLAY_CLOSE_TAB },
   { "keyboardOverlayCloseWindow", IDS_KEYBOARD_OVERLAY_CLOSE_WINDOW },
+  { "keyboardOverlayContextMenu", IDS_KEYBOARD_OVERLAY_CONTEXT_MENU },
   { "keyboardOverlayCopy", IDS_KEYBOARD_OVERLAY_COPY },
   { "keyboardOverlayCut", IDS_KEYBOARD_OVERLAY_CUT },
   { "keyboardOverlayCycleThroughInputMethods",
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index c2a0138e..e6e1390 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3124,6 +3124,10 @@
     ],
     'chrome_browser_webrtc_sources': [
       # TODO(brettw) should webrtc_log_list.cc go here?
+      'browser/media/audio_debug_recordings_handler.cc',
+      'browser/media/audio_debug_recordings_handler.h',
+      'browser/media/webrtc_event_log_handler.cc',
+      'browser/media/webrtc_event_log_handler.h',
       'browser/media/webrtc_log_uploader.cc',
       'browser/media/webrtc_log_uploader.h',
       'browser/media/webrtc_log_util.cc',
@@ -3667,6 +3671,15 @@
             '../components/components.gyp:generate_version_info',
           ],
         }],
+        ['OS == "win" and kasko_failed_rdv_reports == 1', {
+          'sources': [
+            'app/chrome_crash_reporter_client.cc',
+            'app/chrome_crash_reporter_client.h',
+          ],
+          'dependencies': [
+            '../components/components.gyp:crash_component_lib',
+          ],
+        }],
         ['use_nss_certs==1', {
           'sources': [ '<@(chrome_browser_nss_sources)' ],
           'conditions': [
@@ -3827,6 +3840,7 @@
             'chrome_process_finder',
             'chrome_watcher_client',
             'installer_util_strings',
+            'kasko_util',
             '../chrome/common_constants.gyp:version_header',
             '../chrome_elf/chrome_elf.gyp:chrome_elf',
             '../chrome_elf/chrome_elf.gyp:chrome_elf_constants',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index 2cf079d1..81691b3 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -213,6 +213,7 @@
       'browser/extensions/api/web_request/web_request_apitest.cc',
       'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc',
       'browser/extensions/api/webrtc_from_web_accessible_resource_browsertest.cc',
+      'browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc',
       'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc',
       'browser/extensions/api/webstore_private/webstore_private_apitest.cc',
       'browser/extensions/app_background_page_apitest.cc',
@@ -2477,6 +2478,7 @@
         ['enable_webrtc==0', {
           'sources!': [
             'browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc',
+            'browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc',
             'browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc',
             'browser/media/webrtc_apprtc_browsertest.cc',
             'browser/media/webrtc_audio_quality_browsertest.cc',
diff --git a/chrome/chrome_watcher/BUILD.gn b/chrome/chrome_watcher/BUILD.gn
index c31088f..67c993d 100644
--- a/chrome/chrome_watcher/BUILD.gn
+++ b/chrome/chrome_watcher/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//chrome/version.gni")
+import("//third_party/kasko/kasko.gni")
 
 source_set("client") {
   sources = [
@@ -14,6 +15,26 @@
   ]
 }
 
+if (enable_kasko) {
+  source_set("kasko_util") {
+    sources = [
+      "kasko_util.cc",
+      "kasko_util.h",
+    ]
+    deps = [
+      "//base",
+      "//components/crash/content/app",
+      "//third_party/kasko",
+    ]
+  }
+} else {
+  group("kasko_util") {
+    public_deps = [
+      "//third_party/kasko:kasko_features",
+    ]
+  }
+}
+
 process_version("chrome_watcher_resources") {
   template_file = chrome_version_rc_template
   sources = [
@@ -32,13 +53,12 @@
   deps = [
     ":chrome_watcher_resources",
     ":client",
+    ":kasko_util",
     "//base",
     "//base:base_static",
     "//build/config/sanitizers:deps",
     "//chrome/installer/util:with_no_strings",
     "//components/browser_watcher",
-    "//components/crash/content/app",
-    "//third_party/kasko",
   ]
   ldflags = [ "/DEF:" + rebase_path("chrome_watcher.def", root_build_dir) ]
   configs -= [ "//build/config/win:console" ]
diff --git a/chrome/chrome_watcher/chrome_watcher.gypi b/chrome/chrome_watcher/chrome_watcher.gypi
index ad051fc..422e88d1 100644
--- a/chrome/chrome_watcher/chrome_watcher.gypi
+++ b/chrome/chrome_watcher/chrome_watcher.gypi
@@ -9,6 +9,39 @@
     '../../build/util/version.gypi',
     '../../build/win_precompile.gypi',
   ],
+  'conditions': [
+    ['kasko==1', {
+      'targets': [
+        {
+          'target_name': 'kasko_util',
+          'type': 'static_library',
+          'sources': [
+            'kasko_util.cc',
+            'kasko_util.h',
+          ],
+          'dependencies': [
+            'chrome_watcher_client',
+            '../base/base.gyp:base',
+            '../third_party/kasko/kasko.gyp:kasko',
+            '../components/components.gyp:crash_component'
+          ],
+          'export_dependent_settings': [
+            '../third_party/kasko/kasko.gyp:kasko',
+          ],
+        },
+      ],
+    }, {  # 'kasko==0'
+      'targets': [
+        {
+          'target_name': 'kasko_util',
+          'type': 'none',
+          'dependencies': [
+            '../third_party/kasko/kasko.gyp:kasko_features',
+          ],
+        },
+      ],
+    }],
+  ],  # 'conditions'
   'targets': [
     {
       'target_name': 'chrome_watcher_resources',
@@ -61,11 +94,10 @@
       'dependencies': [
         'chrome_watcher_client',
         'chrome_watcher_resources',
+        'kasko_util',
         'installer_util',
         '../base/base.gyp:base',
         '../components/components.gyp:browser_watcher',
-        '../third_party/kasko/kasko.gyp:kasko',
-        '../components/components.gyp:crash_component'
       ],
       'msvs_settings': {
         'VCLinkerTool': {
diff --git a/chrome/chrome_watcher/chrome_watcher_main.cc b/chrome/chrome_watcher/chrome_watcher_main.cc
index 1976c7a..95ead77 100644
--- a/chrome/chrome_watcher/chrome_watcher_main.cc
+++ b/chrome/chrome_watcher/chrome_watcher_main.cc
@@ -34,17 +34,13 @@
 #include "base/win/win_util.h"
 
 #include "chrome/chrome_watcher/chrome_watcher_main_api.h"
+#include "chrome/chrome_watcher/kasko_util.h"
 #include "chrome/installer/util/util_constants.h"
 #include "components/browser_watcher/endsession_watcher_window_win.h"
 #include "components/browser_watcher/exit_code_watcher_win.h"
 #include "components/browser_watcher/window_hang_monitor_win.h"
 #include "third_party/kasko/kasko_features.h"
 
-#if BUILDFLAG(ENABLE_KASKO)
-#include "components/crash/content/app/crashpad.h"
-#include "syzygy/kasko/api/reporter.h"
-#endif
-
 namespace {
 
 // Use the same log facility as Chrome for convenience.
@@ -197,161 +193,6 @@
   }
 }
 
-#if BUILDFLAG(ENABLE_KASKO)
-// Helper function for determining the crash server to use. Defaults to the
-// standard crash server, but can be overridden via an environment variable.
-// Enables easy integration testing.
-void GetKaskoCrashServerUrl(base::string16* crash_server) {
-  const char kKaskoCrashServerUrl[] = "KASKO_CRASH_SERVER_URL";
-  static const wchar_t kDefaultKaskoCrashServerUrl[] =
-      L"https://clients2.google.com/cr/report";
-
-  auto env = base::Environment::Create();
-  std::string env_var;
-  if (env->GetVar(kKaskoCrashServerUrl, &env_var)) {
-    base::UTF8ToWide(env_var.c_str(), env_var.size(), crash_server);
-  } else {
-    *crash_server = kDefaultKaskoCrashServerUrl;
-  }
-}
-
-// Helper function for determining the crash reports directory to use. Defaults
-// to the browser data directory, but can be overridden via an environment
-// variable. Enables easy integration testing.
-void GetKaskoCrashReportsBaseDir(const base::char16* browser_data_directory,
-                                 base::FilePath* base_dir) {
-  const char kKaskoCrashReportBaseDir[] = "KASKO_CRASH_REPORTS_BASE_DIR";
-  auto env = base::Environment::Create();
-  std::string env_var;
-  if (env->GetVar(kKaskoCrashReportBaseDir, &env_var)) {
-    base::string16 wide_env_var;
-    base::UTF8ToWide(env_var.c_str(), env_var.size(), &wide_env_var);
-    *base_dir = base::FilePath(wide_env_var);
-  } else {
-    *base_dir = base::FilePath(browser_data_directory);
-  }
-}
-
-void DumpHungBrowserProcess(DWORD main_thread_id,
-                            const base::string16& channel,
-                            const base::Process& process) {
-  // Read the Crashpad module annotations for the process.
-  std::vector<kasko::api::CrashKey> annotations;
-  crash_reporter::ReadMainModuleAnnotationsForKasko(process, &annotations);
-
-  // Add a special crash key to distinguish reports generated for a hung
-  // process.
-  annotations.push_back(kasko::api::CrashKey{L"hung-process", L"1"});
-
-  std::vector<const base::char16*> key_buffers;
-  std::vector<const base::char16*> value_buffers;
-  for (const auto& crash_key : annotations) {
-    key_buffers.push_back(crash_key.name);
-    value_buffers.push_back(crash_key.value);
-  }
-  key_buffers.push_back(nullptr);
-  value_buffers.push_back(nullptr);
-
-  // Synthesize an exception for the main thread. Populate the record with the
-  // current context of the thread to get the stack trace bucketed on the crash
-  // backend.
-  CONTEXT thread_context = {};
-  EXCEPTION_RECORD exception_record = {};
-  exception_record.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
-  EXCEPTION_POINTERS exception_pointers = {&exception_record, &thread_context};
-
-  base::win::ScopedHandle main_thread(::OpenThread(
-      THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
-      FALSE, main_thread_id));
-
-  bool have_context = false;
-  if (main_thread.IsValid()) {
-    DWORD suspend_count = ::SuspendThread(main_thread.Get());
-    const DWORD kSuspendFailed = static_cast<DWORD>(-1);
-    if (suspend_count != kSuspendFailed) {
-      // Best effort capture of the context.
-      thread_context.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_SEGMENTS |
-                                    CONTEXT_INTEGER | CONTEXT_CONTROL;
-      if (::GetThreadContext(main_thread.Get(), &thread_context) == TRUE)
-        have_context = true;
-
-      ::ResumeThread(main_thread.Get());
-    }
-  }
-
-  // TODO(erikwright): Make the dump-type channel-dependent.
-  if (have_context) {
-    kasko::api::SendReportForProcess(
-        process.Handle(), main_thread_id, &exception_pointers,
-        kasko::api::LARGER_DUMP_TYPE, key_buffers.data(), value_buffers.data());
-  } else {
-    kasko::api::SendReportForProcess(process.Handle(), 0, nullptr,
-                                     kasko::api::LARGER_DUMP_TYPE,
-                                     key_buffers.data(), value_buffers.data());
-  }
-}
-
-void LoggedDeregisterEventSource(HANDLE event_source_handle) {
-  if (!::DeregisterEventSource(event_source_handle))
-    DPLOG(ERROR) << "DeregisterEventSource";
-}
-
-void LoggedLocalFree(PSID sid) {
-  if (::LocalFree(sid) != nullptr)
-    DPLOG(ERROR) << "LocalFree";
-}
-
-void OnCrashReportUpload(void* context,
-                         const base::char16* report_id,
-                         const base::char16* minidump_path,
-                         const base::char16* const* keys,
-                         const base::char16* const* values) {
-  // Open the event source.
-  HANDLE event_source_handle = ::RegisterEventSource(NULL, L"Chrome");
-  if (!event_source_handle) {
-    PLOG(ERROR) << "RegisterEventSource";
-    return;
-  }
-  // Ensure cleanup on scope exit.
-  base::ScopedClosureRunner deregister_event_source(
-      base::Bind(&LoggedDeregisterEventSource, event_source_handle));
-
-  // Get the user's SID for the log record.
-  base::string16 sid_string;
-  PSID sid = nullptr;
-  if (base::win::GetUserSidString(&sid_string)) {
-    if (!sid_string.empty()) {
-      if (!::ConvertStringSidToSid(sid_string.c_str(), &sid))
-        DPLOG(ERROR) << "ConvertStringSidToSid";
-      DCHECK(sid);
-    }
-  }
-  // Ensure cleanup on scope exit.
-  base::ScopedClosureRunner free_sid(
-      base::Bind(&LoggedLocalFree, base::Unretained(sid)));
-
-  // Generate the message.
-  // Note that the format of this message must match the consumer in
-  // chrome/browser/crash_upload_list_win.cc.
-  base::string16 message =
-      L"Crash uploaded. Id=" + base::string16(report_id) + L".";
-
-  // Matches Omaha.
-  const int kCrashUploadEventId = 2;
-
-  // Report the event.
-  const base::char16* strings[] = {message.c_str()};
-  if (!::ReportEvent(event_source_handle, EVENTLOG_INFORMATION_TYPE,
-                     0,  // category
-                     kCrashUploadEventId, sid,
-                     1,  // count
-                     0, strings, nullptr)) {
-    DPLOG(ERROR);
-  }
-}
-
-#endif  // BUILDFLAG(ENABLE_KASKO)
-
 }  // namespace
 
 // The main entry point to the watcher, declared as extern "C" to avoid name
@@ -379,31 +220,17 @@
   base::Callback<void(const base::Process&)> on_hung_callback;
 
 #if BUILDFLAG(ENABLE_KASKO)
-  base::string16 crash_server;
-  GetKaskoCrashServerUrl(&crash_server);
+  bool launched_kasko = InitializeKaskoReporter(GetKaskoEndpoint(process.Pid()),
+                                                browser_data_directory);
 
-  base::FilePath crash_reports_base_dir;
-  GetKaskoCrashReportsBaseDir(browser_data_directory, &crash_reports_base_dir);
-  bool launched_kasko = kasko::api::InitializeReporter(
-      GetKaskoEndpoint(process.Pid()).c_str(),
-      crash_server.c_str(),
-      crash_reports_base_dir
-          .Append(L"Crash Reports")
-          .value()
-          .c_str(),
-      crash_reports_base_dir
-          .Append(kPermanentlyFailedReportsSubdir)
-          .value()
-          .c_str(),
-      &OnCrashReportUpload, nullptr);
 #if BUILDFLAG(ENABLE_KASKO_HANG_REPORTS)
   // Only activate hang reports for the canary channel. For testing purposes,
   // Chrome instances with no channels will also report hangs.
   if (launched_kasko &&
       (base::StringPiece16(channel_name) == L"" ||
        base::StringPiece16(channel_name) == installer::kChromeChannelCanary)) {
-    on_hung_callback =
-        base::Bind(&DumpHungBrowserProcess, main_thread_id, channel_name);
+    on_hung_callback = base::Bind(&DumpHungProcess, main_thread_id,
+                                  channel_name, L"hung-process");
   }
 #endif  // BUILDFLAG(ENABLE_KASKO_HANG_REPORTS)
 #endif  // BUILDFLAG(ENABLE_KASKO)
@@ -432,7 +259,7 @@
 
 #if BUILDFLAG(ENABLE_KASKO)
   if (launched_kasko)
-    kasko::api::ShutdownReporter();
+    ShutdownKaskoReporter();
 #endif  // BUILDFLAG(ENABLE_KASKO)
 
   // Wind logging down.
diff --git a/chrome/chrome_watcher/kasko_util.cc b/chrome/chrome_watcher/kasko_util.cc
new file mode 100644
index 0000000..120f105d
--- /dev/null
+++ b/chrome/chrome_watcher/kasko_util.cc
@@ -0,0 +1,241 @@
+// 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 "chrome/chrome_watcher/kasko_util.h"
+
+#include <sddl.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/base_paths.h"
+#include "base/bind.h"
+#include "base/callback_helpers.h"
+#include "base/environment.h"
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/path_service.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/win_util.h"
+
+#include "chrome/chrome_watcher/chrome_watcher_main_api.h"
+#include "components/crash/content/app/crashpad.h"
+#include "syzygy/kasko/api/reporter.h"
+
+namespace {
+
+// Helper function for determining the crash server to use. Defaults to the
+// standard crash server, but can be overridden via an environment variable.
+// Enables easy integration testing.
+base::string16 GetKaskoCrashServerUrl() {
+  static const char kKaskoCrashServerUrl[] = "KASKO_CRASH_SERVER_URL";
+  static const wchar_t kDefaultKaskoCrashServerUrl[] =
+      L"https://clients2.google.com/cr/report";
+
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
+  std::string env_var;
+  if (env->GetVar(kKaskoCrashServerUrl, &env_var)) {
+    return base::UTF8ToUTF16(env_var);
+  }
+  return kDefaultKaskoCrashServerUrl;
+}
+
+// Helper function for determining the crash reports directory to use. Defaults
+// to the browser data directory, but can be overridden via an environment
+// variable. Enables easy integration testing.
+base::FilePath GetKaskoCrashReportsBaseDir(
+    const base::char16* browser_data_directory) {
+  static const char kKaskoCrashReportBaseDir[] = "KASKO_CRASH_REPORTS_BASE_DIR";
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
+  std::string env_var;
+  if (env->GetVar(kKaskoCrashReportBaseDir, &env_var)) {
+    return base::FilePath(base::UTF8ToUTF16(env_var));
+  }
+  return base::FilePath(browser_data_directory);
+}
+
+struct EventSourceDeregisterer {
+  using pointer = HANDLE;
+  void operator()(HANDLE event_source_handle) const {
+    if (!::DeregisterEventSource(event_source_handle))
+      DPLOG(ERROR) << "DeregisterEventSource";
+  }
+};
+using ScopedEventSourceHandle =
+    std::unique_ptr<HANDLE, EventSourceDeregisterer>;
+
+struct SidDeleter {
+  using pointer = PSID;
+  void operator()(PSID sid) const {
+    if (::LocalFree(sid) != nullptr)
+      DPLOG(ERROR) << "LocalFree";
+  }
+};
+using ScopedSid = std::unique_ptr<PSID, SidDeleter>;
+
+void OnCrashReportUpload(void* context,
+                         const base::char16* report_id,
+                         const base::char16* minidump_path,
+                         const base::char16* const* keys,
+                         const base::char16* const* values) {
+  // Open the event source.
+  ScopedEventSourceHandle event_source_handle(
+      ::RegisterEventSource(nullptr, L"Chrome"));
+  if (!event_source_handle) {
+    PLOG(ERROR) << "RegisterEventSource";
+    return;
+  }
+
+  // Get the user's SID for the log record.
+  base::string16 sid_string;
+  PSID sid = nullptr;
+  if (base::win::GetUserSidString(&sid_string) && !sid_string.empty()) {
+    if (!::ConvertStringSidToSid(sid_string.c_str(), &sid))
+      DPLOG(ERROR) << "ConvertStringSidToSid";
+    DCHECK(sid);
+  }
+  // Ensure cleanup on scope exit.
+  ScopedSid scoped_sid;
+  if (sid)
+    scoped_sid.reset(sid);
+
+  // Generate the message.
+  // Note that the format of this message must match the consumer in
+  // chrome/browser/crash_upload_list_win.cc.
+  base::string16 message =
+      L"Crash uploaded. Id=" + base::string16(report_id) + L".";
+
+  // Matches Omaha.
+  const int kCrashUploadEventId = 2;
+
+  // Report the event.
+  const base::char16* strings[] = {message.c_str()};
+  if (!::ReportEvent(event_source_handle.get(), EVENTLOG_INFORMATION_TYPE,
+                     0,  // category
+                     kCrashUploadEventId, sid,
+                     1,  // count
+                     0, strings, nullptr)) {
+    DPLOG(ERROR);
+  }
+}
+
+void AddCrashKey(const wchar_t *key, const wchar_t *value,
+                 std::vector<kasko::api::CrashKey> *crash_keys) {
+  DCHECK(key);
+  DCHECK(value);
+  DCHECK(crash_keys);
+
+  kasko::api::CrashKey crash_key;
+  std::wcsncpy(crash_key.name, key, kasko::api::CrashKey::kNameMaxLength - 1);
+  std::wcsncpy(crash_key.value, value,
+               kasko::api::CrashKey::kValueMaxLength - 1);
+  crash_keys->push_back(crash_key);
+}
+
+}  // namespace
+
+bool InitializeKaskoReporter(const base::string16& endpoint,
+                             const base::char16* browser_data_directory) {
+  base::string16 crash_server = GetKaskoCrashServerUrl();
+  base::FilePath crash_reports_base_dir =
+      GetKaskoCrashReportsBaseDir(browser_data_directory);
+
+  return kasko::api::InitializeReporter(
+      endpoint.c_str(),
+      crash_server.c_str(),
+      crash_reports_base_dir.Append(L"Crash Reports").value().c_str(),
+      crash_reports_base_dir.Append(kPermanentlyFailedReportsSubdir)
+          .value()
+          .c_str(),
+      &OnCrashReportUpload,
+      nullptr);
+}
+
+void ShutdownKaskoReporter() {
+  kasko::api::ShutdownReporter();
+}
+
+bool EnsureTargetProcessValidForCapture(const base::Process& process) {
+  // Ensure the target process shares the current process's executable name.
+  base::FilePath exe_self;
+  if (!PathService::Get(base::FILE_EXE, &exe_self))
+    return false;
+
+  wchar_t exe_name_other[MAX_PATH];
+  DWORD exe_name_other_len = arraysize(exe_name_other);
+  // Note: requesting the Win32 path format.
+  if (::QueryFullProcessImageName(process.Handle(), 0, exe_name_other,
+                                  &exe_name_other_len) == 0) {
+    DPLOG(ERROR) << "Failed to get executable name for other process";
+    return false;
+  }
+
+  // QueryFullProcessImageName's documentation does not specify behavior when
+  // the buffer is too small, but we know that GetModuleFileNameEx succeeds and
+  // truncates the returned name in such a case. Given that paths of arbitrary
+  // length may exist, the conservative approach is to reject names when
+  // the returned length is that of the buffer.
+  if (exe_name_other_len > 0 &&
+      exe_name_other_len < arraysize(exe_name_other)) {
+    return base::FilePath::CompareEqualIgnoreCase(exe_self.value(),
+                                                  exe_name_other);
+  }
+  return false;
+}
+
+void DumpHungProcess(DWORD main_thread_id, const base::string16& channel,
+                     const base::char16* key, const base::Process& process) {
+  // Read the Crashpad module annotations for the process.
+  std::vector<kasko::api::CrashKey> annotations;
+  crash_reporter::ReadMainModuleAnnotationsForKasko(process, &annotations);
+  AddCrashKey(key, L"1", &annotations);
+
+  std::vector<const base::char16*> key_buffers;
+  std::vector<const base::char16*> value_buffers;
+  for (const auto& crash_key : annotations) {
+    key_buffers.push_back(crash_key.name);
+    value_buffers.push_back(crash_key.value);
+  }
+  key_buffers.push_back(nullptr);
+  value_buffers.push_back(nullptr);
+
+  // Synthesize an exception for the main thread. Populate the record with the
+  // current context of the thread to get the stack trace bucketed on the crash
+  // backend.
+  CONTEXT thread_context = {};
+  EXCEPTION_RECORD exception_record = {};
+  exception_record.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
+  EXCEPTION_POINTERS exception_pointers = {&exception_record, &thread_context};
+
+  base::win::ScopedHandle main_thread(::OpenThread(
+      THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION,
+      FALSE, main_thread_id));
+
+  bool have_context = false;
+  if (main_thread.IsValid()) {
+    DWORD suspend_count = ::SuspendThread(main_thread.Get());
+    const DWORD kSuspendFailed = static_cast<DWORD>(-1);
+    if (suspend_count != kSuspendFailed) {
+      // Best effort capture of the context.
+      thread_context.ContextFlags = CONTEXT_FLOATING_POINT | CONTEXT_SEGMENTS |
+                                    CONTEXT_INTEGER | CONTEXT_CONTROL;
+      if (::GetThreadContext(main_thread.Get(), &thread_context) == TRUE)
+        have_context = true;
+
+      ::ResumeThread(main_thread.Get());
+    }
+  }
+
+  // TODO(manzagop): consider making the dump-type channel-dependent.
+  if (have_context) {
+    kasko::api::SendReportForProcess(
+        process.Handle(), main_thread_id, &exception_pointers,
+        kasko::api::LARGER_DUMP_TYPE, key_buffers.data(), value_buffers.data());
+  } else {
+    kasko::api::SendReportForProcess(process.Handle(), 0, nullptr,
+                                     kasko::api::LARGER_DUMP_TYPE,
+                                     key_buffers.data(), value_buffers.data());
+  }
+}
diff --git a/chrome/chrome_watcher/kasko_util.h b/chrome/chrome_watcher/kasko_util.h
new file mode 100644
index 0000000..30d7bc8
--- /dev/null
+++ b/chrome/chrome_watcher/kasko_util.h
@@ -0,0 +1,30 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_WATCHER_KASKO_UTIL_H_
+#define CHROME_CHROME_WATCHER_KASKO_UTIL_H_
+
+#include <windows.h>
+
+#include "base/process/process.h"
+#include "base/strings/string16.h"
+
+// Initialize a Kasko reporter.
+bool InitializeKaskoReporter(const base::string16& endpoint,
+                             const base::char16* browser_data_directory);
+
+// Shut down a Kasko reporter.
+void ShutdownKaskoReporter();
+
+// Ensure that a process is a valid target for report capture. This is to
+// defend against against races that exist in getting a Process from a window
+// name (potential HWND and process id recycling).
+bool EnsureTargetProcessValidForCapture(const base::Process& process);
+
+// Dumps a process. A crash key will be added to the report, using the provided
+// key as name and "1" as its value.
+void DumpHungProcess(DWORD main_thread_id, const base::string16 &channel,
+                     const base::char16* key, const base::Process& process);
+
+#endif  // CHROME_CHROME_WATCHER_KASKO_UTIL_H_
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 64a43400..1cf1ac1 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -499,6 +499,10 @@
 // This only has an effect if QUIC protocol is enabled.
 const char kEnableQuicPortSelection[]       = "enable-quic-port-selection";
 
+// If the WebRTC logging private API is active, enables WebRTC event logging.
+const char kEnableWebRtcEventLoggingFromExtension[] =
+    "enable-webrtc-event-logging-from-extension";
+
 // Enables support for HTTP alternative services.
 const char kEnableAlternativeServices[] = "enable-alternative-services";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 6ae3495..d6d0012 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -144,6 +144,7 @@
 extern const char kEnablePushApiBackgroundMode[];
 extern const char kEnableQuic[];
 extern const char kEnableQuicPortSelection[];
+extern const char kEnableWebRtcEventLoggingFromExtension[];
 extern const char kEnableAlternativeServices[];
 extern const char kEnableSessionCrashedBubble[];
 extern const char kEnableSettingsWindow[];
diff --git a/chrome/common/extensions/api/webrtc_logging_private.idl b/chrome/common/extensions/api/webrtc_logging_private.idl
index 0f900f9..fadea0e 100644
--- a/chrome/common/extensions/api/webrtc_logging_private.idl
+++ b/chrome/common/extensions/api/webrtc_logging_private.idl
@@ -28,23 +28,23 @@
     long? guestProcessId;
   };
 
-  // This contains information about the result of audio debug recordings.
-  dictionary AudioDebugRecordingsInfo {
+  // This contains information about the result of audio debug recordings or
+  // WebRTC event logs.
+  dictionary RecordingInfo {
     // Absolute path prefix for the files with the audio debug recordings.
     DOMString prefixPath;
 
-    // Indicates if recording was stopped.
+    // Indicates if recording was stopped (either by a timed callback after the
+    // time limit has elapsed, or by a manual call).
     boolean didStop;
 
     // Indicates if recording was stopped manually through a
-    // stopAudioDebugRecordings() call.
+    // stopAudioDebugRecordings() or stopWebRtcEventLogging() call.
     boolean didManualStop;
   };
 
-
   callback GenericDoneCallback = void ();
-  callback AudioDebugRecordingsCallback =
-      void (AudioDebugRecordingsInfo info);
+  callback RecordingDoneCallback = void (RecordingInfo info);
   callback UploadDoneCallback = void (UploadResult result);
 
   interface Functions {
@@ -137,15 +137,35 @@
     // that recording has not stopped.
     // If |seconds| is negative, startAudioDebugRecordings() fails.
     static void startAudioDebugRecordings(RequestInfo request,
-                             DOMString securityOrigin,
-                             long seconds,
-                             AudioDebugRecordingsCallback callback);
+                                          DOMString securityOrigin,
+                                          long seconds,
+                                          RecordingDoneCallback callback);
 
     // Stops audio debug recordings.  |callback| is invoked once recording
     // stops. If there is no recording in progress, stopAudioDebugRecordings()
     // fails.
     static void stopAudioDebugRecordings(RequestInfo request,
-                            DOMString securityOrigin,
-                            AudioDebugRecordingsCallback callback);
+                                         DOMString securityOrigin,
+                                         RecordingDoneCallback callback);
+
+    // Starts WebRTC event logging.
+    // startWebRtcEventLogging() logs the most recent events that happened
+    // before the call, and then keep logging for |seconds| seconds into the
+    // future. |callback| is invoked once the logging stops.
+    // If |seconds| is zero, the logging will continue until
+    // stopWebRtcEventLogging() is explicitly called. In this case,
+    // |callback| is invoked once recording starts and will report
+    // that recording has not stopped.
+    // If |seconds| is negative, startWebRtcEventLogging() fails.
+    static void startWebRtcEventLogging(RequestInfo request,
+                                        DOMString securityOrigin,
+                                        long seconds,
+                                        RecordingDoneCallback callback);
+
+    // Stops RTC event logging. |callback| is invoked once the logging stops.
+    // If there is no recording in progress, stopWebRtcEventLogging() fails.
+    static void stopWebRtcEventLogging(RequestInfo request,
+                                       DOMString securityOrigin,
+                                       RecordingDoneCallback callback);
   };
 };
diff --git a/chrome/common/extensions/docs/examples/api/desktopCapture/background.js b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
index 332b4515..30e4779cf 100644
--- a/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
+++ b/chrome/common/extensions/docs/examples/api/desktopCapture/background.js
@@ -6,7 +6,7 @@
   chrome.app.window.create('index.html', {
     bounds: {
       width: 1080,
-      height: 420
+      height: 550
     }
   });
 });
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 4ec9491..fa288164 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -8,13 +8,13 @@
 #include <shlobj.h>
 #include <time.h>
 
+#include <memory>
 #include <string>
 
 #include "base/files/file_enumerator.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -134,7 +134,7 @@
   reg_path.push_back(base::FilePath::kSeparators[0]);
   reg_path.append(installer::kChromeExe);
   VLOG(1) << "Adding Chrome to Media player list at " << reg_path;
-  scoped_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem(
+  std::unique_ptr<WorkItem> work_item(WorkItem::CreateCreateRegKeyWorkItem(
       HKEY_LOCAL_MACHINE, reg_path, WorkItem::kWow64Default));
 
   // if the operation fails we log the error but still continue
@@ -184,7 +184,7 @@
     const base::FilePath& src_path,
     const base::FilePath& temp_path,
     const Version& new_version,
-    scoped_ptr<Version>* current_version) {
+    std::unique_ptr<Version>* current_version) {
   DCHECK(current_version);
 
   installer_state.UpdateStage(installer::BUILDING);
@@ -192,7 +192,7 @@
   current_version->reset(installer_state.GetCurrentVersion(original_state));
   installer::SetCurrentVersionCrashKey(current_version->get());
 
-  scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
 
   AddInstallWorkItems(original_state,
                       installer_state,
@@ -581,7 +581,7 @@
   installer_state.UpdateStage(installer::CREATING_VISUAL_MANIFEST);
   CreateVisualElementsManifest(src_path, new_version);
 
-  scoped_ptr<Version> existing_version;
+  std::unique_ptr<Version> existing_version;
   InstallStatus result = InstallNewVersion(original_state, installer_state,
       setup_path, archive_path, src_path, install_temp_path, new_version,
       &existing_version);
@@ -705,7 +705,7 @@
   // TODO(gab): This should really perform all registry only update steps (i.e.,
   // something between InstallOrUpdateProduct and AddActiveSetupWorkItems, but
   // this takes care of what is most required for now).
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
   AddActiveSetupWorkItems(installer_state, installed_version, chrome,
                           work_item_list.get());
   if (!work_item_list->Do()) {
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index 0eefee2..ac53127 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -2,9 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/setup/install.h"
+
 #include <objbase.h>
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 
 #include "base/base_paths.h"
@@ -12,7 +15,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_number_conversions.h"
@@ -21,7 +23,6 @@
 #include "base/test/test_shortcut_win.h"
 #include "base/version.h"
 #include "base/win/shortcut.h"
-#include "chrome/installer/setup/install.h"
 #include "chrome/installer/setup/install_worker.h"
 #include "chrome/installer/setup/setup_constants.h"
 #include "chrome/installer/util/browser_distribution.h"
@@ -261,8 +262,8 @@
 
   BrowserDistribution* dist_;
   base::FilePath chrome_exe_;
-  scoped_ptr<installer::Product> product_;
-  scoped_ptr<installer::MasterPreferences> prefs_;
+  std::unique_ptr<installer::Product> product_;
+  std::unique_ptr<installer::MasterPreferences> prefs_;
 
   base::ScopedTempDir temp_dir_;
   base::ScopedTempDir fake_user_desktop_;
@@ -270,11 +271,11 @@
   base::ScopedTempDir fake_user_quick_launch_;
   base::ScopedTempDir fake_start_menu_;
   base::ScopedTempDir fake_common_start_menu_;
-  scoped_ptr<base::ScopedPathOverride> user_desktop_override_;
-  scoped_ptr<base::ScopedPathOverride> common_desktop_override_;
-  scoped_ptr<base::ScopedPathOverride> user_quick_launch_override_;
-  scoped_ptr<base::ScopedPathOverride> start_menu_override_;
-  scoped_ptr<base::ScopedPathOverride> common_start_menu_override_;
+  std::unique_ptr<base::ScopedPathOverride> user_desktop_override_;
+  std::unique_ptr<base::ScopedPathOverride> common_desktop_override_;
+  std::unique_ptr<base::ScopedPathOverride> user_quick_launch_override_;
+  std::unique_ptr<base::ScopedPathOverride> start_menu_override_;
+  std::unique_ptr<base::ScopedPathOverride> common_start_menu_override_;
 
   base::FilePath user_desktop_shortcut_;
   base::FilePath user_quick_launch_shortcut_;
@@ -345,7 +346,7 @@
 }
 
 TEST_F(InstallShortcutTest, CreateAllShortcutsButDesktopShortcut) {
-  scoped_ptr<installer::MasterPreferences> prefs_no_desktop(
+  std::unique_ptr<installer::MasterPreferences> prefs_no_desktop(
       GetFakeMasterPrefs(true, false));
   installer::CreateOrUpdateShortcuts(
       chrome_exe_, *product_, *prefs_no_desktop, installer::CURRENT_USER,
@@ -358,7 +359,7 @@
 }
 
 TEST_F(InstallShortcutTest, CreateAllShortcutsButQuickLaunchShortcut) {
-  scoped_ptr<installer::MasterPreferences> prefs_no_ql(
+  std::unique_ptr<installer::MasterPreferences> prefs_no_ql(
       GetFakeMasterPrefs(false, true));
   installer::CreateOrUpdateShortcuts(
       chrome_exe_, *product_, *prefs_no_ql, installer::CURRENT_USER,
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index 5878c004..830a3a3a 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -13,6 +13,7 @@
 #include <stdint.h>
 #include <time.h>
 
+#include <memory>
 #include <vector>
 
 #include "base/bind.h"
@@ -21,7 +22,6 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -190,7 +190,7 @@
   if (work_item.IsRollback() && !remove_on_rollback)
     return true;
 
-  scoped_ptr<FirewallManager> manager =
+  std::unique_ptr<FirewallManager> manager =
       FirewallManager::Create(dist, chrome_path);
   if (!manager) {
     LOG(ERROR) << "Failed creating a FirewallManager. Continuing with install.";
@@ -905,7 +905,7 @@
   // the 'cpv' value with the critical update version (if present), and the
   // 'cmd' value with the rename command to run.
   {
-    scoped_ptr<WorkItemList> in_use_update_work_items(
+    std::unique_ptr<WorkItemList> in_use_update_work_items(
         WorkItem::CreateConditionalWorkItemList(
             new ConditionRunIfFileExists(new_chrome_exe)));
     in_use_update_work_items->set_log_message("InUseUpdateWorkItemList");
@@ -979,7 +979,7 @@
 
   // Append work items that will be executed if this was NOT an in-use update.
   {
-    scoped_ptr<WorkItemList> regular_update_work_items(
+    std::unique_ptr<WorkItemList> regular_update_work_items(
         WorkItem::CreateConditionalWorkItemList(
             new Not(new ConditionRunIfFileExists(new_chrome_exe))));
     regular_update_work_items->set_log_message("RegularUpdateWorkItemList");
diff --git a/chrome/installer/setup/install_worker_unittest.cc b/chrome/installer/setup/install_worker_unittest.cc
index b8c0fc4d..8907a53a 100644
--- a/chrome/installer/setup/install_worker_unittest.cc
+++ b/chrome/installer/setup/install_worker_unittest.cc
@@ -301,7 +301,7 @@
 
   MockInstallationState* BuildChromeInstallationState(bool system_level,
                                                       bool multi_install) {
-    scoped_ptr<MockInstallationState> installation_state(
+    std::unique_ptr<MockInstallationState> installation_state(
         new MockInstallationState());
     AddChromeToInstallationState(system_level, multi_install,
                                  installation_state.get());
@@ -313,7 +313,8 @@
       bool multi_install,
       const InstallationState& machine_state,
       InstallerState::Operation operation) {
-    scoped_ptr<MockInstallerState> installer_state(new MockInstallerState());
+    std::unique_ptr<MockInstallerState> installer_state(
+        new MockInstallerState());
 
     InstallerState::Level level = system_install ?
         InstallerState::SYSTEM_LEVEL : InstallerState::USER_LEVEL;
@@ -349,7 +350,7 @@
       BrowserDistribution* dist =
           BrowserDistribution::GetSpecificDistribution(
               BrowserDistribution::CHROME_BINARIES);
-      scoped_ptr<Product> product(new Product(dist));
+      std::unique_ptr<Product> product(new Product(dist));
       product->SetOption(installer::kOptionMultiInstall, true);
       installer_state->AddProduct(&product);
     }
@@ -370,7 +371,7 @@
       BrowserDistribution* dist =
           BrowserDistribution::GetSpecificDistribution(
               BrowserDistribution::CHROME_BROWSER);
-      scoped_ptr<Product> product(new Product(dist));
+      std::unique_ptr<Product> product(new Product(dist));
       if (installer_state->is_multi_install())
         product->SetOption(installer::kOptionMultiInstall, true);
       installer_state->AddProduct(&product);
@@ -391,7 +392,7 @@
       BrowserDistribution* dist =
           BrowserDistribution::GetSpecificDistribution(
               BrowserDistribution::CHROME_FRAME);
-      scoped_ptr<Product> product(new Product(dist));
+      std::unique_ptr<Product> product(new Product(dist));
       if (installer_state->is_multi_install())
         product->SetOption(installer::kOptionMultiInstall, true);
       installer_state->AddProduct(&product);
@@ -403,7 +404,7 @@
       bool multi_install,
       const InstallationState& machine_state,
       InstallerState::Operation operation) {
-    scoped_ptr<MockInstallerState> installer_state(
+    std::unique_ptr<MockInstallerState> installer_state(
         BuildBasicInstallerState(system_install, multi_install, machine_state,
                                  operation));
     if (multi_install) {
@@ -426,7 +427,7 @@
       InstallerState::Operation operation) {
     // This method only works for installation/upgrade.
     DCHECK(operation != InstallerState::UNINSTALL);
-    scoped_ptr<MockInstallerState> installer_state(
+    std::unique_ptr<MockInstallerState> installer_state(
         BuildBasicInstallerState(system_install, multi_install, machine_state,
                                  operation));
     if (multi_install)
@@ -436,8 +437,8 @@
   }
 
  protected:
-  scoped_ptr<Version> current_version_;
-  scoped_ptr<Version> new_version_;
+  std::unique_ptr<Version> current_version_;
+  std::unique_ptr<Version> new_version_;
   base::FilePath archive_path_;
   base::FilePath installation_path_;
   base::FilePath setup_path_;
@@ -455,26 +456,25 @@
 
   const HKEY kRegRoot = system_level ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
   static const wchar_t kRegKeyPath[] = L"Software\\Chromium\\test";
-  scoped_ptr<CreateRegKeyWorkItem> create_reg_key_work_item(
-      WorkItem::CreateCreateRegKeyWorkItem(
-          kRegRoot, kRegKeyPath, WorkItem::kWow64Default));
-  scoped_ptr<SetRegValueWorkItem> set_reg_value_work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> create_reg_key_work_item(
+      WorkItem::CreateCreateRegKeyWorkItem(kRegRoot, kRegKeyPath,
+                                           WorkItem::kWow64Default));
+  std::unique_ptr<SetRegValueWorkItem> set_reg_value_work_item(
       WorkItem::CreateSetRegValueWorkItem(
           kRegRoot, kRegKeyPath, WorkItem::kWow64Default, L"", L"", false));
-  scoped_ptr<DeleteTreeWorkItem> delete_tree_work_item(
+  std::unique_ptr<DeleteTreeWorkItem> delete_tree_work_item(
       WorkItem::CreateDeleteTreeWorkItem(base::FilePath(), base::FilePath(),
                                          std::vector<base::FilePath>()));
-  scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_work_item(
+  std::unique_ptr<DeleteRegKeyWorkItem> delete_reg_key_work_item(
       WorkItem::CreateDeleteRegKeyWorkItem(kRegRoot, kRegKeyPath,
                                            WorkItem::kWow64Default));
 
-  scoped_ptr<InstallationState> installation_state(
+  std::unique_ptr<InstallationState> installation_state(
       BuildChromeInstallationState(system_level, multi_install));
 
-  scoped_ptr<InstallerState> installer_state(
-      BuildChromeInstallerState(system_level, multi_install,
-                                *installation_state,
-                                InstallerState::SINGLE_INSTALL_OR_UPDATE));
+  std::unique_ptr<InstallerState> installer_state(BuildChromeInstallerState(
+      system_level, multi_install, *installation_state,
+      InstallerState::SINGLE_INSTALL_OR_UPDATE));
 
   // Set up some expectations.
   // TODO(robertshield): Set up some real expectations.
@@ -538,8 +538,8 @@
                                    installer_state_.get());
   }
 
-  scoped_ptr<MockInstallationState> installation_state_;
-  scoped_ptr<MockInstallerState> installer_state_;
+  std::unique_ptr<MockInstallationState> installation_state_;
+  std::unique_ptr<MockInstallerState> installer_state_;
   bool system_level_;
   bool multi_install_;
   HKEY root_key_;
@@ -565,7 +565,7 @@
   MockWorkItemList work_item_list;
 
   // Per-machine single-install Chrome is installed.
-  scoped_ptr<MockInstallationState> installation_state(
+  std::unique_ptr<MockInstallationState> installation_state(
       BuildChromeInstallationState(system_level, false));
 
   MockProductState cf_state;
@@ -577,10 +577,9 @@
       BrowserDistribution::CHROME_FRAME, cf_state);
 
   // Prepare per-machine multi-install Chrome for installation.
-  scoped_ptr<MockInstallerState> installer_state(
-      BuildChromeInstallerState(system_level, multi_install,
-                                *installation_state,
-                                InstallerState::MULTI_INSTALL));
+  std::unique_ptr<MockInstallerState> installer_state(BuildChromeInstallerState(
+      system_level, multi_install, *installation_state,
+      InstallerState::MULTI_INSTALL));
 
   // Expect the multi Client State key to be created for the binaries.
 #if defined(GOOGLE_CHROME_BUILD)
@@ -637,7 +636,7 @@
   const bool multi_install = true;
   MockWorkItemList work_item_list;
 
-  scoped_ptr<MockInstallationState> installation_state(
+  std::unique_ptr<MockInstallationState> installation_state(
       BuildChromeInstallationState(system_level, multi_install));
 
   MockProductState chrome_state;
@@ -648,10 +647,9 @@
   installation_state->SetProductState(system_level,
       BrowserDistribution::CHROME_BROWSER, chrome_state);
 
-  scoped_ptr<MockInstallerState> installer_state(
-      BuildChromeInstallerState(system_level, multi_install,
-                                *installation_state,
-                                InstallerState::MULTI_INSTALL));
+  std::unique_ptr<MockInstallerState> installer_state(BuildChromeInstallerState(
+      system_level, multi_install, *installation_state,
+      InstallerState::MULTI_INSTALL));
 
   // Expect the multi Client State key to be created.
   BrowserDistribution* multi_dist =
@@ -732,8 +730,8 @@
   static const bool system_level_ = false;
   static const wchar_t kRegKeyPath[];
   HKEY root_key_;
-  scoped_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
-  scoped_ptr<MockInstallationState> machine_state_;
+  std::unique_ptr<DeleteRegKeyWorkItem> delete_reg_key_item_;
+  std::unique_ptr<MockInstallationState> machine_state_;
   StrictMock<MockWorkItemList> work_item_list_;
 };
 
@@ -743,9 +741,8 @@
 
 TEST_F(QuickEnableAbsentTest, CleanInstallSingleChrome) {
   // Install single Chrome on a clean system.
-  scoped_ptr<MockInstallerState> installer_state(
-      BuildBasicInstallerState(system_level_, true, *machine_state_,
-                                InstallerState::MULTI_UPDATE));
+  std::unique_ptr<MockInstallerState> installer_state(BuildBasicInstallerState(
+      system_level_, true, *machine_state_, InstallerState::MULTI_UPDATE));
   AddQuickEnableChromeFrameWorkItems(*installer_state, &work_item_list_);
 }
 
@@ -773,7 +770,7 @@
   // Loop over machine states: {No product, Chrome, CF, Chrome + CF}.
   for (int i_mach = 0; i_mach < (1 << NUM_TYPE); ++i_mach) {
     // i_mach is the machine state before operation, as bit mask.
-    scoped_ptr<MockInstallationState> machine_state(
+    std::unique_ptr<MockInstallationState> machine_state(
         new MockInstallationState());
     if ((i_mach & (1 << TYPE_BROWSER)) != 0) {  // Add Chrome.
       AddChromeToInstallationState(system_level, multi_install,
@@ -789,7 +786,7 @@
 
       // Loop over product types to operate on: {TYPE_BROWSER, TYPE_CF}.
       for (int i_type_op = 0; i_type_op < NUM_TYPE; ++i_type_op) {
-        scoped_ptr<InstallerState> installer_state;
+        std::unique_ptr<InstallerState> installer_state;
         if (i_type_op == TYPE_BROWSER) {
           installer_state.reset(BuildChromeInstallerState(
               system_level, multi_install, *machine_state, op));
diff --git a/chrome/installer/setup/installer_crash_reporter_client.cc b/chrome/installer/setup/installer_crash_reporter_client.cc
index 65ff331..fa1ac1f0 100644
--- a/chrome/installer/setup/installer_crash_reporter_client.cc
+++ b/chrome/installer/setup/installer_crash_reporter_client.cc
@@ -43,7 +43,7 @@
   // MUST match server-side configuration.
   *product_name = base::ASCIIToUTF16(PRODUCT_SHORTNAME_STRING);
 
-  scoped_ptr<FileVersionInfo> version_info(
+  std::unique_ptr<FileVersionInfo> version_info(
       FileVersionInfo::CreateFileVersionInfo(exe_path));
   if (version_info) {
     *version = version_info->product_version();
@@ -119,7 +119,7 @@
 }
 
 bool InstallerCrashReporterClient::IsRunningUnattended() {
-  scoped_ptr<base::Environment> env(base::Environment::Create());
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
   return env->HasVar(env_vars::kHeadless);
 }
 
diff --git a/chrome/installer/setup/installer_crash_reporting.cc b/chrome/installer/setup/installer_crash_reporting.cc
index ae92e0b1..b6c5161 100644
--- a/chrome/installer/setup/installer_crash_reporting.cc
+++ b/chrome/installer/setup/installer_crash_reporting.cc
@@ -115,7 +115,7 @@
                                                         "Chrome Installer");
 
   // Set up the metrics client id (a la child_process_logging::Init()).
-  scoped_ptr<metrics::ClientInfo> client_info =
+  std::unique_ptr<metrics::ClientInfo> client_info =
       GoogleUpdateSettings::LoadMetricsClientInfo();
   if (client_info)
     crash_keys::SetMetricsClientIdFromGUID(client_info->client_id);
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index 085fe656..82f0ab26 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -11,6 +11,7 @@
 #include <stddef.h>
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 #include "base/at_exit.h"
@@ -20,7 +21,6 @@
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
@@ -173,7 +173,7 @@
 
 // Returns NULL if no compressed archive is available for processing, otherwise
 // returns a patch helper configured to uncompress and patch.
-scoped_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper(
+std::unique_ptr<installer::ArchivePatchHelper> CreateChromeArchiveHelper(
     const base::FilePath& setup_exe,
     const base::CommandLine& command_line,
     const installer::InstallerState& installer_state,
@@ -195,7 +195,7 @@
       LOG(ERROR) << installer::switches::kInstallArchive << "="
                  << compressed_archive.value() << " not found.";
     }
-    return scoped_ptr<installer::ArchivePatchHelper>();
+    return std::unique_ptr<installer::ArchivePatchHelper>();
   }
 
   // chrome.7z is either extracted directly from the compressed archive into the
@@ -206,11 +206,9 @@
   // Specify an empty path for the patch source since it isn't yet known that
   // one is needed. It will be supplied in UncompressAndPatchChromeArchive if it
   // is.
-  return scoped_ptr<installer::ArchivePatchHelper>(
-      new installer::ArchivePatchHelper(working_directory,
-                                        compressed_archive,
-                                        base::FilePath(),
-                                        target));
+  return std::unique_ptr<installer::ArchivePatchHelper>(
+      new installer::ArchivePatchHelper(working_directory, compressed_archive,
+                                        base::FilePath(), target));
 }
 
 // Returns the MSI product ID from the ClientState key that is populated for MSI
@@ -392,7 +390,7 @@
                        .Append(installer::kInstallTempDir).value();
     return installer::RENAME_FAILED;
   }
-  scoped_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItemList> install_list(WorkItem::CreateWorkItemList());
   // Move chrome.exe to old_chrome.exe, then move new_chrome.exe to chrome.exe.
   install_list->AddMoveTreeWorkItem(chrome_exe.value(),
                                     chrome_old_exe.value(),
@@ -486,8 +484,8 @@
       // A product other than Chrome is being installed in multi-install mode,
       // and Chrome is already present. Add Chrome to the set of products
       // (making it multi-install in the process) so that it is updated, too.
-      scoped_ptr<Product> multi_chrome(new Product(
-          BrowserDistribution::GetSpecificDistribution(
+      std::unique_ptr<Product> multi_chrome(
+          new Product(BrowserDistribution::GetSpecificDistribution(
               BrowserDistribution::CHROME_BROWSER)));
       multi_chrome->SetOption(installer::kOptionMultiInstall, true);
       chrome = installer_state->AddProduct(&multi_chrome);
@@ -1235,7 +1233,7 @@
         installer_state->FindProduct(BrowserDistribution::CHROME_BROWSER);
     installer::InstallStatus status = installer::INVALID_STATE_FOR_OPTION;
     if (chrome_install) {
-      scoped_ptr<FileVersionInfo> version_info(
+      std::unique_ptr<FileVersionInfo> version_info(
           FileVersionInfo::CreateFileVersionInfo(setup_exe));
       const base::Version installed_version(
           base::UTF16ToUTF8(version_info->product_version()));
@@ -1431,7 +1429,7 @@
           installer::switches::kPreviousVersion));
     }
 
-    scoped_ptr<ArchivePatchHelper> archive_helper(
+    std::unique_ptr<ArchivePatchHelper> archive_helper(
         CreateChromeArchiveHelper(setup_exe, cmd_line, installer_state,
                                   unpack_path));
     if (archive_helper) {
@@ -1492,8 +1490,8 @@
   VLOG(1) << "unpacked to " << unpack_path.value();
   base::FilePath src_path(
       unpack_path.Append(kInstallSourceChromeDir));
-  scoped_ptr<Version>
-      installer_version(GetMaxVersionFromArchiveDir(src_path));
+  std::unique_ptr<Version> installer_version(
+      GetMaxVersionFromArchiveDir(src_path));
   if (!installer_version.get()) {
     LOG(ERROR) << "Did not find any valid version in installer.";
     install_status = INVALID_ARCHIVE;
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 3a27b224..93826c8 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -103,14 +103,14 @@
   // TODO(tommi): The version directory really should match the version of
   // setup.exe.  To begin with, we should at least DCHECK that that's true.
 
-  scoped_ptr<Version> max_version(new Version("0.0.0.0"));
+  std::unique_ptr<Version> max_version(new Version("0.0.0.0"));
   bool version_found = false;
 
   while (!version_enum.Next().empty()) {
     base::FileEnumerator::FileInfo find_data = version_enum.GetInfo();
     VLOG(1) << "directory found: " << find_data.GetName().value();
 
-    scoped_ptr<Version> found_version(
+    std::unique_ptr<Version> found_version(
         new Version(base::UTF16ToASCII(find_data.GetName().value())));
     if (found_version->IsValid() &&
         found_version->CompareTo(*max_version.get()) > 0) {
@@ -144,7 +144,7 @@
     if (base::PathExists(patch_source))
       return patch_source;
   }
-  scoped_ptr<Version> version(
+  std::unique_ptr<Version> version(
       installer::GetMaxVersionFromArchiveDir(installer_state.target_path()));
   if (version) {
     patch_source = installer_state.GetInstallerDirectory(*version)
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 10b4540..c466f9c 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -7,13 +7,13 @@
 #include <windows.h>
 #include <shlobj.h>
 
+#include <memory>
 #include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/process/process_handle.h"
@@ -59,7 +59,7 @@
   EXPECT_FALSE(::GetTokenInformation(token.Get(), TokenPrivileges, NULL, 0,
                                      &size));
 
-  scoped_ptr<BYTE[]> privileges_bytes(new BYTE[size]);
+  std::unique_ptr<BYTE[]> privileges_bytes(new BYTE[size]);
   TOKEN_PRIVILEGES* privileges =
       reinterpret_cast<TOKEN_PRIVILEGES*>(privileges_bytes.get());
 
@@ -73,7 +73,7 @@
   // anything longer will obviously not be equal to |privilege_name|.
   const DWORD desired_size = static_cast<DWORD>(wcslen(privilege_name));
   const DWORD buffer_size = desired_size + 1;
-  scoped_ptr<wchar_t[]> name_buffer(new wchar_t[buffer_size]);
+  std::unique_ptr<wchar_t[]> name_buffer(new wchar_t[buffer_size]);
   for (int i = privileges->PrivilegeCount - 1; i >= 0 ; --i) {
     LUID_AND_ATTRIBUTES& luid_and_att = privileges->Privileges[i];
     DWORD size = buffer_size;
@@ -96,7 +96,7 @@
   base::FilePath chrome_dir = test_dir.path().AppendASCII("1.0.0.0");
   base::CreateDirectory(chrome_dir);
   ASSERT_TRUE(base::PathExists(chrome_dir));
-  scoped_ptr<Version> version(
+  std::unique_ptr<Version> version(
       installer::GetMaxVersionFromArchiveDir(test_dir.path()));
   ASSERT_EQ(version->GetString(), "1.0.0.0");
 
@@ -203,7 +203,7 @@
  public:
   // Applies |priority_class|, returning an instance if a change was made.
   // Otherwise, returns an empty scoped_ptr.
-  static scoped_ptr<ScopedPriorityClass> Create(DWORD priority_class);
+  static std::unique_ptr<ScopedPriorityClass> Create(DWORD priority_class);
   ~ScopedPriorityClass();
 
  private:
@@ -212,7 +212,7 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedPriorityClass);
 };
 
-scoped_ptr<ScopedPriorityClass> ScopedPriorityClass::Create(
+std::unique_ptr<ScopedPriorityClass> ScopedPriorityClass::Create(
     DWORD priority_class) {
   HANDLE this_process = ::GetCurrentProcess();
   DWORD original_priority_class = ::GetPriorityClass(this_process);
@@ -221,11 +221,11 @@
     BOOL result = ::SetPriorityClass(this_process, priority_class);
     EXPECT_NE(FALSE, result);
     if (result) {
-      return scoped_ptr<ScopedPriorityClass>(
+      return std::unique_ptr<ScopedPriorityClass>(
           new ScopedPriorityClass(original_priority_class));
     }
   }
-  return scoped_ptr<ScopedPriorityClass>();
+  return std::unique_ptr<ScopedPriorityClass>();
 }
 
 ScopedPriorityClass::ScopedPriorityClass(DWORD original_priority_class)
@@ -264,7 +264,7 @@
 // Launching a subprocess below normal priority class drops it to bg mode for
 // sufficiently recent operating systems.
 TEST(SetupUtilTest, AdjustFromBelowNormalPriority) {
-  scoped_ptr<ScopedPriorityClass> below_normal =
+  std::unique_ptr<ScopedPriorityClass> below_normal =
       ScopedPriorityClass::Create(BELOW_NORMAL_PRIORITY_CLASS);
   ASSERT_TRUE(below_normal);
   if (base::win::GetVersion() > base::win::VERSION_SERVER_2003)
@@ -376,8 +376,8 @@
   base::ScopedTempDir test_dir_;
   Version product_version_;
   Version max_version_;
-  scoped_ptr<FakeInstallationState> original_state_;
-  scoped_ptr<installer::InstallerState> installer_state_;
+  std::unique_ptr<FakeInstallationState> original_state_;
+  std::unique_ptr<installer::InstallerState> installer_state_;
 
  private:
   registry_util::RegistryOverrideManager registry_override_manager_;
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index b5d41c1..3bd54a7e 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -138,8 +138,8 @@
 
   // Apply the new channel value to all other products and to the multi package.
   if (modified) {
-    scoped_ptr<WorkItemList>
-        update_list(WorkItem::CreateNoRollbackWorkItemList());
+    std::unique_ptr<WorkItemList> update_list(
+        WorkItem::CreateNoRollbackWorkItemList());
     std::vector<BrowserDistribution::Type> dist_types;
     for (size_t i = 0; i < BrowserDistribution::NUM_TYPES; ++i) {
       BrowserDistribution::Type other_dist_type =
@@ -158,7 +158,7 @@
 // Processes uninstall WorkItems from install_worker in no-rollback-list.
 void ProcessChromeWorkItems(const InstallerState& installer_state,
                             const Product& product) {
-  scoped_ptr<WorkItemList> work_item_list(
+  std::unique_ptr<WorkItemList> work_item_list(
       WorkItem::CreateNoRollbackWorkItemList());
   AddOsUpgradeWorkItems(installer_state, base::FilePath(), Version(), product,
                         work_item_list.get());
@@ -173,7 +173,8 @@
 }
 
 void ProcessIELowRightsPolicyWorkItems(const InstallerState& installer_state) {
-  scoped_ptr<WorkItemList> work_items(WorkItem::CreateNoRollbackWorkItemList());
+  std::unique_ptr<WorkItemList> work_items(
+      WorkItem::CreateNoRollbackWorkItemList());
   AddDeleteOldIELowRightsPolicyWorkItems(installer_state, work_items.get());
   work_items->Do();
   RefreshElevationPolicy();
@@ -1072,7 +1073,7 @@
 
 void UninstallFirewallRules(BrowserDistribution* dist,
                             const base::FilePath& chrome_exe) {
-  scoped_ptr<FirewallManager> manager =
+  std::unique_ptr<FirewallManager> manager =
       FirewallManager::Create(dist, chrome_exe);
   if (manager)
     manager->RemoveFirewallRules();
@@ -1294,7 +1295,7 @@
       base::FilePath dll_folder = installer_state.target_path().AppendASCII(
           product_state->version().GetString());
 
-      scoped_ptr<WorkItemList> unreg_work_item_list(
+      std::unique_ptr<WorkItemList> unreg_work_item_list(
           WorkItem::CreateWorkItemList());
 
       AddRegisterComDllWorkItems(dll_folder,
diff --git a/chrome/installer/util/beacons.cc b/chrome/installer/util/beacons.cc
index 1aae130..dac4458 100644
--- a/chrome/installer/util/beacons.cc
+++ b/chrome/installer/util/beacons.cc
@@ -6,6 +6,7 @@
 
 #include <stdint.h>
 
+#include "base/memory/ptr_util.h"
 #include "base/win/registry.h"
 #include "base/win/win_util.h"
 #include "chrome/installer/util/app_registration_data.h"
@@ -50,26 +51,26 @@
 
 namespace installer_util {
 
-scoped_ptr<Beacon> MakeLastOsUpgradeBeacon(
+std::unique_ptr<Beacon> MakeLastOsUpgradeBeacon(
     bool system_install,
     const AppRegistrationData& registration_data) {
-  return make_scoped_ptr(new Beacon(L"LastOsUpgrade", Beacon::BeaconType::LAST,
-                                    Beacon::BeaconScope::PER_INSTALL,
-                                    system_install, registration_data));
+  return base::WrapUnique(new Beacon(L"LastOsUpgrade", Beacon::BeaconType::LAST,
+                                     Beacon::BeaconScope::PER_INSTALL,
+                                     system_install, registration_data));
 }
 
-scoped_ptr<Beacon> MakeLastWasDefaultBeacon(
+std::unique_ptr<Beacon> MakeLastWasDefaultBeacon(
     bool system_install,
     const AppRegistrationData& registration_data) {
-  return make_scoped_ptr(new Beacon(L"LastWasDefault", Beacon::BeaconType::LAST,
-                                    Beacon::BeaconScope::PER_USER,
-                                    system_install, registration_data));
+  return base::WrapUnique(new Beacon(
+      L"LastWasDefault", Beacon::BeaconType::LAST,
+      Beacon::BeaconScope::PER_USER, system_install, registration_data));
 }
 
-scoped_ptr<Beacon> MakeFirstNotDefaultBeacon(
+std::unique_ptr<Beacon> MakeFirstNotDefaultBeacon(
     bool system_install,
     const AppRegistrationData& registration_data) {
-  return make_scoped_ptr(new Beacon(
+  return base::WrapUnique(new Beacon(
       L"FirstNotDefault", Beacon::BeaconType::FIRST,
       Beacon::BeaconScope::PER_USER, system_install, registration_data));
 }
diff --git a/chrome/installer/util/beacons.h b/chrome/installer/util/beacons.h
index bec393e..e1bdaa68 100644
--- a/chrome/installer/util/beacons.h
+++ b/chrome/installer/util/beacons.h
@@ -7,8 +7,9 @@
 
 #include <windows.h>
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
@@ -40,19 +41,19 @@
 class Beacon;
 
 // Returns a Beacon representing the last time the machine's OS was ugpraded.
-scoped_ptr<Beacon> MakeLastOsUpgradeBeacon(
+std::unique_ptr<Beacon> MakeLastOsUpgradeBeacon(
     bool system_install,
     const AppRegistrationData& registration_data);
 
 // Returns a Beacon representing the last time Chrome was the user's default
 // browser.
-scoped_ptr<Beacon> MakeLastWasDefaultBeacon(
+std::unique_ptr<Beacon> MakeLastWasDefaultBeacon(
     bool system_install,
     const AppRegistrationData& registration_data);
 
 // Returns a Beacon representing the first time Chrome was not the user's
 // default browser.
-scoped_ptr<Beacon> MakeFirstNotDefaultBeacon(
+std::unique_ptr<Beacon> MakeFirstNotDefaultBeacon(
     bool system_install,
     const AppRegistrationData& registration_data);
 
diff --git a/chrome/installer/util/beacons_unittest.cc b/chrome/installer/util/beacons_unittest.cc
index 2465dd3c..2553912 100644
--- a/chrome/installer/util/beacons_unittest.cc
+++ b/chrome/installer/util/beacons_unittest.cc
@@ -223,9 +223,9 @@
 
 // Tests that the default browser beacons work as expected.
 TEST_P(DefaultBrowserBeaconTest, All) {
-  scoped_ptr<Beacon> last_was_default(MakeLastWasDefaultBeacon(
+  std::unique_ptr<Beacon> last_was_default(MakeLastWasDefaultBeacon(
       system_install_, distribution_->GetAppRegistrationData()));
-  scoped_ptr<Beacon> first_not_default(MakeFirstNotDefaultBeacon(
+  std::unique_ptr<Beacon> first_not_default(MakeFirstNotDefaultBeacon(
       system_install_, distribution_->GetAppRegistrationData()));
 
   ASSERT_TRUE(last_was_default->Get().is_null());
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index c9be46d..d680d96 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -15,6 +15,7 @@
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
+#include "base/memory/ptr_util.h"
 #include "base/win/registry.h"
 #include "base/win/windows_version.h"
 #include "chrome/common/chrome_icon_resources_win.h"
@@ -54,13 +55,12 @@
 
 BrowserDistribution::BrowserDistribution()
     : type_(CHROME_BROWSER),
-      app_reg_data_(make_scoped_ptr(
-          new NonUpdatingAppRegistrationData(L"Software\\Chromium"))) {
-}
+      app_reg_data_(base::WrapUnique(
+          new NonUpdatingAppRegistrationData(L"Software\\Chromium"))) {}
 
 BrowserDistribution::BrowserDistribution(
     Type type,
-    scoped_ptr<AppRegistrationData> app_reg_data)
+    std::unique_ptr<AppRegistrationData> app_reg_data)
     : type_(type), app_reg_data_(std::move(app_reg_data)) {}
 
 BrowserDistribution::~BrowserDistribution() {}
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 18f7ece..2baf37d2 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -7,11 +7,11 @@
 #ifndef CHROME_INSTALLER_UTIL_BROWSER_DISTRIBUTION_H_
 #define CHROME_INSTALLER_UTIL_BROWSER_DISTRIBUTION_H_
 
+#include <memory>
 #include <string>
 
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/version.h"
 #include "build/build_config.h"
@@ -162,7 +162,8 @@
   virtual bool HasUserExperiments();
 
  protected:
-  BrowserDistribution(Type type, scoped_ptr<AppRegistrationData> app_reg_data);
+  BrowserDistribution(Type type,
+                      std::unique_ptr<AppRegistrationData> app_reg_data);
 
   template<class DistributionClass>
   static BrowserDistribution* GetOrCreateBrowserDistribution(
@@ -170,7 +171,7 @@
 
   const Type type_;
 
-  scoped_ptr<AppRegistrationData> app_reg_data_;
+  std::unique_ptr<AppRegistrationData> app_reg_data_;
 
  private:
   BrowserDistribution();
diff --git a/chrome/installer/util/chrome_frame_distribution.cc b/chrome/installer/util/chrome_frame_distribution.cc
index d5311b3..37ab875 100644
--- a/chrome/installer/util/chrome_frame_distribution.cc
+++ b/chrome/installer/util/chrome_frame_distribution.cc
@@ -26,9 +26,8 @@
 ChromeFrameDistribution::ChromeFrameDistribution()
     : BrowserDistribution(
           CHROME_FRAME,
-          scoped_ptr<AppRegistrationData>(
-              new UpdatingAppRegistrationData(kChromeFrameGuid))) {
-}
+          std::unique_ptr<AppRegistrationData>(
+              new UpdatingAppRegistrationData(kChromeFrameGuid))) {}
 
 base::string16 ChromeFrameDistribution::GetBaseAppName() {
   return L"Google Chrome Frame";
diff --git a/chrome/installer/util/chromium_binaries_distribution.cc b/chrome/installer/util/chromium_binaries_distribution.cc
index c1a278c9..e457063 100644
--- a/chrome/installer/util/chromium_binaries_distribution.cc
+++ b/chrome/installer/util/chromium_binaries_distribution.cc
@@ -19,16 +19,16 @@
 }  // namespace
 
 ChromiumBinariesDistribution::ChromiumBinariesDistribution()
-    : BrowserDistribution(
-          CHROME_BINARIES,
-          scoped_ptr<AppRegistrationData>(new NonUpdatingAppRegistrationData(
-              base::string16(L"Software\\").append(kChromiumBinariesName)))),
+    : BrowserDistribution(CHROME_BINARIES,
+                          std::unique_ptr<AppRegistrationData>(
+                              new NonUpdatingAppRegistrationData(
+                                  base::string16(L"Software\\")
+                                      .append(kChromiumBinariesName)))),
       browser_distribution_(
-          BrowserDistribution::GetSpecificDistribution(CHROME_BROWSER)) {
-}
+          BrowserDistribution::GetSpecificDistribution(CHROME_BROWSER)) {}
 
 ChromiumBinariesDistribution::ChromiumBinariesDistribution(
-    scoped_ptr<AppRegistrationData> app_reg_data)
+    std::unique_ptr<AppRegistrationData> app_reg_data)
     : BrowserDistribution(CHROME_BINARIES, std::move(app_reg_data)),
       browser_distribution_(
           BrowserDistribution::GetSpecificDistribution(CHROME_BROWSER)) {}
diff --git a/chrome/installer/util/chromium_binaries_distribution.h b/chrome/installer/util/chromium_binaries_distribution.h
index 6f879d3..5da24d4 100644
--- a/chrome/installer/util/chromium_binaries_distribution.h
+++ b/chrome/installer/util/chromium_binaries_distribution.h
@@ -7,10 +7,10 @@
 #ifndef CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_
 #define CHROME_INSTALLER_UTIL_CHROMIUM_BINARIES_DISTRIBUTION_H_
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/installer/util/browser_distribution.h"
 
 class ChromiumBinariesDistribution : public BrowserDistribution {
@@ -55,7 +55,7 @@
   ChromiumBinariesDistribution();
 
   explicit ChromiumBinariesDistribution(
-      scoped_ptr<AppRegistrationData> app_reg_data);
+      std::unique_ptr<AppRegistrationData> app_reg_data);
 
   BrowserDistribution* browser_distribution_;
 
diff --git a/chrome/installer/util/conditional_work_item_list.h b/chrome/installer/util/conditional_work_item_list.h
index ae5cdc9..834b1e0 100644
--- a/chrome/installer/util/conditional_work_item_list.h
+++ b/chrome/installer/util/conditional_work_item_list.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_INSTALLER_UTIL_CONDITIONAL_WORK_ITEM_LIST_H_
 #define CHROME_INSTALLER_UTIL_CONDITIONAL_WORK_ITEM_LIST_H_
 
-#include "chrome/installer/util/work_item_list.h"
+#include <memory>
 
 #include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
+#include "chrome/installer/util/work_item_list.h"
 
 // A WorkItemList subclass that permits conditionally executing a set of
 // WorkItems.
@@ -28,7 +28,7 @@
  protected:
   // Pointer to a Condition that is used to determine whether to run this
   // WorkItemList.
-  scoped_ptr<Condition> condition_;
+  std::unique_ptr<Condition> condition_;
 };
 
 
@@ -54,7 +54,7 @@
   bool ShouldRun() const override;
 
  private:
-  scoped_ptr<WorkItem::Condition> original_condition_;
+  std::unique_ptr<WorkItem::Condition> original_condition_;
 };
 
 #endif  // CHROME_INSTALLER_UTIL_CONDITIONAL_WORK_ITEM_LIST_H_
diff --git a/chrome/installer/util/copy_tree_work_item_unittest.cc b/chrome/installer/util/copy_tree_work_item_unittest.cc
index 5d7a5e0..bffdd15 100644
--- a/chrome/installer/util/copy_tree_work_item_unittest.cc
+++ b/chrome/installer/util/copy_tree_work_item_unittest.cc
@@ -2,18 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/copy_tree_work_item.h"
+
 #include <windows.h>
 
 #include <fstream>
+#include <memory>
 
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/threading/platform_thread.h"
-#include "chrome/installer/util/copy_tree_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -90,12 +91,9 @@
   file_name_to = file_name_to.AppendASCII("File_To.txt");
 
   // test Do()
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                       file_name_to,
-                                       temp_dir_.path(),
-                                       WorkItem::ALWAYS,
-                                       base::FilePath()));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(), WorkItem::ALWAYS,
+      base::FilePath()));
 
   EXPECT_TRUE(work_item->Do());
 
@@ -132,12 +130,9 @@
   ASSERT_TRUE(base::PathExists(file_name_to));
 
   // test Do() with always_overwrite being true.
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                       file_name_to,
-                                       temp_dir_.path(),
-                                       WorkItem::ALWAYS,
-                                       base::FilePath()));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(), WorkItem::ALWAYS,
+      base::FilePath()));
 
   EXPECT_TRUE(work_item->Do());
 
@@ -202,12 +197,9 @@
   ASSERT_TRUE(base::PathExists(file_name_to));
 
   // test Do() with always_overwrite being true.
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                       file_name_to,
-                                       temp_dir_.path(),
-                                       WorkItem::ALWAYS,
-                                       base::FilePath()));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(), WorkItem::ALWAYS,
+      base::FilePath()));
 
   EXPECT_TRUE(work_item->Do());
 
@@ -286,12 +278,10 @@
 
   {
     // test Do().
-    scoped_ptr<CopyTreeWorkItem> work_item(
-        WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                         file_name_to,
-                                         temp_dir_.path(),
-                                         WorkItem::IF_DIFFERENT,
-                                         base::FilePath()));
+    std::unique_ptr<CopyTreeWorkItem> work_item(
+        WorkItem::CreateCopyTreeWorkItem(
+            file_name_from, file_name_to, temp_dir_.path(),
+            WorkItem::IF_DIFFERENT, base::FilePath()));
 
     EXPECT_TRUE(work_item->Do());
 
@@ -350,12 +340,9 @@
                        NULL, NULL, &si, &pi));
 
   // test Do().
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                       file_name_to,
-                                       temp_dir_.path(),
-                                       WorkItem::IF_DIFFERENT,
-                                       base::FilePath()));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(), WorkItem::IF_DIFFERENT,
+      base::FilePath()));
 
   EXPECT_TRUE(work_item->Do());
 
@@ -430,12 +417,9 @@
                        NULL, NULL, &si, &pi));
 
   // test Do().
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                       file_name_to,
-                                       temp_dir_.path(),
-                                       WorkItem::NEW_NAME_IF_IN_USE,
-                                       alternate_to));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(),
+      WorkItem::NEW_NAME_IF_IN_USE, alternate_to));
 
   EXPECT_TRUE(work_item->Do());
 
@@ -532,12 +516,9 @@
   backup_file = backup_file.AppendASCII("File_To");
 
   // test Do().
-  scoped_ptr<CopyTreeWorkItem> work_item(
-      WorkItem::CreateCopyTreeWorkItem(
-          file_name_from,
-          file_name_to, temp_dir_.path(),
-          WorkItem::IF_NOT_PRESENT,
-          base::FilePath()));
+  std::unique_ptr<CopyTreeWorkItem> work_item(WorkItem::CreateCopyTreeWorkItem(
+      file_name_from, file_name_to, temp_dir_.path(), WorkItem::IF_NOT_PRESENT,
+      base::FilePath()));
   EXPECT_TRUE(work_item->Do());
 
   // verify that the source, destination have not changed and backup path
@@ -625,12 +606,10 @@
 
   // test Do().
   {
-    scoped_ptr<CopyTreeWorkItem> work_item(
-        WorkItem::CreateCopyTreeWorkItem(file_name_from,
-                                         file_name_to,
-                                         temp_dir_.path(),
-                                         WorkItem::IF_DIFFERENT,
-                                         base::FilePath()));
+    std::unique_ptr<CopyTreeWorkItem> work_item(
+        WorkItem::CreateCopyTreeWorkItem(
+            file_name_from, file_name_to, temp_dir_.path(),
+            WorkItem::IF_DIFFERENT, base::FilePath()));
 
     EXPECT_TRUE(work_item->Do());
 
@@ -693,11 +672,9 @@
 
   // test Do()
   {
-    scoped_ptr<CopyTreeWorkItem> work_item(
-        WorkItem::CreateCopyTreeWorkItem(dir_name_from,
-                                         dir_name_to,
-                                         temp_dir_.path(),
-                                         WorkItem::ALWAYS,
+    std::unique_ptr<CopyTreeWorkItem> work_item(
+        WorkItem::CreateCopyTreeWorkItem(dir_name_from, dir_name_to,
+                                         temp_dir_.path(), WorkItem::ALWAYS,
                                          base::FilePath()));
 
     EXPECT_TRUE(work_item->Do());
diff --git a/chrome/installer/util/create_dir_work_item_unittest.cc b/chrome/installer/util/create_dir_work_item_unittest.cc
index 07ce874..dca2236 100644
--- a/chrome/installer/util/create_dir_work_item_unittest.cc
+++ b/chrome/installer/util/create_dir_work_item_unittest.cc
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/create_dir_work_item.h"
+
 #include <windows.h>
 
+#include <memory>
+
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
-#include "chrome/installer/util/create_dir_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -35,7 +37,7 @@
   dir_to_create = dir_to_create.AppendASCII("c");
   dir_to_create = dir_to_create.AppendASCII("d");
 
-  scoped_ptr<CreateDirWorkItem> work_item(
+  std::unique_ptr<CreateDirWorkItem> work_item(
       WorkItem::CreateCreateDirWorkItem(dir_to_create));
 
   EXPECT_TRUE(work_item->Do());
@@ -55,7 +57,7 @@
   base::CreateDirectory(dir_to_create);
   ASSERT_TRUE(base::PathExists(dir_to_create));
 
-  scoped_ptr<CreateDirWorkItem> work_item(
+  std::unique_ptr<CreateDirWorkItem> work_item(
       WorkItem::CreateCreateDirWorkItem(dir_to_create));
 
   EXPECT_TRUE(work_item->Do());
@@ -79,7 +81,7 @@
   base::FilePath dir_to_create_3(dir_to_create_2);
   dir_to_create_3 = dir_to_create_3.AppendASCII("ccc");
 
-  scoped_ptr<CreateDirWorkItem> work_item(
+  std::unique_ptr<CreateDirWorkItem> work_item(
       WorkItem::CreateCreateDirWorkItem(dir_to_create_3));
 
   EXPECT_TRUE(work_item->Do());
@@ -112,7 +114,7 @@
   base::FilePath dir_to_create_3(dir_to_create_2);
   dir_to_create_3 = dir_to_create_3.AppendASCII("cccc");
 
-  scoped_ptr<CreateDirWorkItem> work_item(
+  std::unique_ptr<CreateDirWorkItem> work_item(
       WorkItem::CreateCreateDirWorkItem(dir_to_create_3));
 
   EXPECT_TRUE(work_item->Do());
diff --git a/chrome/installer/util/create_reg_key_work_item_unittest.cc b/chrome/installer/util/create_reg_key_work_item_unittest.cc
index 888a0dc..c44ceed5 100644
--- a/chrome/installer/util/create_reg_key_work_item_unittest.cc
+++ b/chrome/installer/util/create_reg_key_work_item_unittest.cc
@@ -2,13 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/create_reg_key_work_item.h"
+
 #include <windows.h>
 
+#include <memory>
+
 #include "base/files/file_path.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/create_reg_key_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -53,7 +55,7 @@
   key_to_create = key_to_create.AppendASCII("c");
   key_to_create = key_to_create.AppendASCII("d");
 
-  scoped_ptr<CreateRegKeyWorkItem> work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> work_item(
       WorkItem::CreateCreateRegKeyWorkItem(
           HKEY_CURRENT_USER, key_to_create.value(), WorkItem::kWow64Default));
 
@@ -79,7 +81,7 @@
   ASSERT_EQ(ERROR_SUCCESS,
       key.Create(HKEY_CURRENT_USER, key_to_create.value().c_str(), KEY_READ));
 
-  scoped_ptr<CreateRegKeyWorkItem> work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> work_item(
       WorkItem::CreateCreateRegKeyWorkItem(
           HKEY_CURRENT_USER, key_to_create.value(), WorkItem::kWow64Default));
 
@@ -107,7 +109,7 @@
   base::FilePath key_to_create_3(key_to_create_2);
   key_to_create_3 = key_to_create_3.AppendASCII("ccc");
 
-  scoped_ptr<CreateRegKeyWorkItem> work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> work_item(
       WorkItem::CreateCreateRegKeyWorkItem(
           HKEY_CURRENT_USER, key_to_create_3.value(), WorkItem::kWow64Default));
 
@@ -146,7 +148,7 @@
   base::FilePath key_to_create_3(key_to_create_2);
   key_to_create_3 = key_to_create_3.AppendASCII("cccc");
 
-  scoped_ptr<CreateRegKeyWorkItem> work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> work_item(
       WorkItem::CreateCreateRegKeyWorkItem(
           HKEY_CURRENT_USER, key_to_create_3.value(), WorkItem::kWow64Default));
 
@@ -176,7 +178,7 @@
   base::FilePath key_to_create(test_root);
   key_to_create = key_to_create.AppendASCII("aaaaa");
 
-  scoped_ptr<CreateRegKeyWorkItem> work_item(
+  std::unique_ptr<CreateRegKeyWorkItem> work_item(
       WorkItem::CreateCreateRegKeyWorkItem(
           HKEY_CURRENT_USER, key_to_create.value(), WorkItem::kWow64Default));
 
diff --git a/chrome/installer/util/delete_after_reboot_helper_unittest.cc b/chrome/installer/util/delete_after_reboot_helper_unittest.cc
index 7dea385..37d58e97 100644
--- a/chrome/installer/util/delete_after_reboot_helper_unittest.cc
+++ b/chrome/installer/util/delete_after_reboot_helper_unittest.cc
@@ -2,16 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/delete_after_reboot_helper.h"
+
 #include <windows.h>
 #include <shlobj.h>
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/files/file_util.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/delete_after_reboot_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
diff --git a/chrome/installer/util/delete_reg_key_work_item_unittest.cc b/chrome/installer/util/delete_reg_key_work_item_unittest.cc
index 19bf03a..65bfdc7 100644
--- a/chrome/installer/util/delete_reg_key_work_item_unittest.cc
+++ b/chrome/installer/util/delete_reg_key_work_item_unittest.cc
@@ -2,15 +2,17 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/delete_reg_key_work_item.h"
+
 #include <windows.h>
 #include <atlsecurity.h>  // NOLINT
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/delete_reg_key_work_item.h"
 #include "chrome/installer/util/registry_test_data.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -40,8 +42,9 @@
   RegKey key;
   for (size_t i = 0; i < arraysize(key_paths); ++i) {
     const std::wstring& key_path = key_paths[i];
-    scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
-        test_data_.root_key(), key_path, WorkItem::kWow64Default));
+    std::unique_ptr<DeleteRegKeyWorkItem> item(
+        WorkItem::CreateDeleteRegKeyWorkItem(test_data_.root_key(), key_path,
+                                             WorkItem::kWow64Default));
     EXPECT_TRUE(item->Do());
     EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
                                       KEY_READ));
@@ -56,8 +59,9 @@
 TEST_F(DeleteRegKeyWorkItemTest, TestEmptyKey) {
   RegKey key;
   const std::wstring& key_path = test_data_.empty_key_path();
-  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
-      test_data_.root_key(), key_path, WorkItem::kWow64Default));
+  std::unique_ptr<DeleteRegKeyWorkItem> item(
+      WorkItem::CreateDeleteRegKeyWorkItem(test_data_.root_key(), key_path,
+                                           WorkItem::kWow64Default));
   EXPECT_TRUE(item->Do());
   EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
                                     KEY_READ));
@@ -72,8 +76,9 @@
 TEST_F(DeleteRegKeyWorkItemTest, TestNonEmptyKey) {
   RegKey key;
   const std::wstring& key_path = test_data_.non_empty_key_path();
-  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
-      test_data_.root_key(), key_path, WorkItem::kWow64Default));
+  std::unique_ptr<DeleteRegKeyWorkItem> item(
+      WorkItem::CreateDeleteRegKeyWorkItem(test_data_.root_key(), key_path,
+                                           WorkItem::kWow64Default));
   EXPECT_TRUE(item->Do());
   EXPECT_NE(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_path.c_str(),
                                     KEY_READ));
@@ -115,8 +120,9 @@
   subkey2.Close();
   subkey.Close();
   key.Close();
-  scoped_ptr<DeleteRegKeyWorkItem> item(WorkItem::CreateDeleteRegKeyWorkItem(
-      test_data_.root_key(), key_name, WorkItem::kWow64Default));
+  std::unique_ptr<DeleteRegKeyWorkItem> item(
+      WorkItem::CreateDeleteRegKeyWorkItem(test_data_.root_key(), key_name,
+                                           WorkItem::kWow64Default));
   EXPECT_FALSE(item->Do());
   EXPECT_EQ(ERROR_SUCCESS, key.Open(test_data_.root_key(), key_name.c_str(),
                                     KEY_QUERY_VALUE));
diff --git a/chrome/installer/util/delete_reg_value_work_item_unittest.cc b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
index 5fea168..55ce612 100644
--- a/chrome/installer/util/delete_reg_value_work_item_unittest.cc
+++ b/chrome/installer/util/delete_reg_value_work_item_unittest.cc
@@ -2,14 +2,16 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/delete_reg_value_work_item.h"
+
 #include <windows.h>
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/delete_reg_value_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -52,13 +54,13 @@
   ASSERT_EQ(ERROR_SUCCESS,
             RegSetValueEx(key.Handle(), kNameEmpty, NULL, REG_SZ, NULL, 0));
 
-  scoped_ptr<DeleteRegValueWorkItem> work_item1(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item1(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr));
-  scoped_ptr<DeleteRegValueWorkItem> work_item2(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item2(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameDword));
-  scoped_ptr<DeleteRegValueWorkItem> work_item3(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item3(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameEmpty));
 
@@ -105,10 +107,10 @@
   EXPECT_FALSE(key.HasValue(kNameStr));
   EXPECT_FALSE(key.HasValue(kNameDword));
 
-  scoped_ptr<DeleteRegValueWorkItem> work_item1(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item1(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr));
-  scoped_ptr<DeleteRegValueWorkItem> work_item2(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item2(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameDword));
 
@@ -132,10 +134,10 @@
   ASSERT_EQ(ERROR_FILE_NOT_FOUND,
             key.Open(HKEY_CURRENT_USER, kTestKey, KEY_READ));
 
-  scoped_ptr<DeleteRegValueWorkItem> work_item1(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item1(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr));
-  scoped_ptr<DeleteRegValueWorkItem> work_item2(
+  std::unique_ptr<DeleteRegValueWorkItem> work_item2(
       WorkItem::CreateDeleteRegValueWorkItem(
           HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameDword));
 
diff --git a/chrome/installer/util/delete_tree_work_item.h b/chrome/installer/util/delete_tree_work_item.h
index d69439a..9af8fdf 100644
--- a/chrome/installer/util/delete_tree_work_item.h
+++ b/chrome/installer/util/delete_tree_work_item.h
@@ -7,11 +7,11 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <vector>
 
 #include "base/files/file_path.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/installer/util/work_item.h"
 
 // A WorkItem subclass that recursively deletes a file system hierarchy at the
@@ -58,12 +58,12 @@
 
   // Contains the paths to the key files. If specified, deletion will be
   // performed only if none of the key files are in use.
-  scoped_ptr<base::FilePath[]> key_paths_;
+  std::unique_ptr<base::FilePath[]> key_paths_;
 
   // Contains the temp directories for the backed-up key files. The directories
   // are created and populated in Do() as-needed. We don't use a standard
   // container for this since base::ScopedTempDir isn't CopyConstructible.
-  scoped_ptr<base::ScopedTempDir[]> key_backup_paths_;
+  std::unique_ptr<base::ScopedTempDir[]> key_backup_paths_;
 
   // The temporary directory into which the original root_path_ has been moved.
   base::ScopedTempDir backup_path_;
diff --git a/chrome/installer/util/delete_tree_work_item_unittest.cc b/chrome/installer/util/delete_tree_work_item_unittest.cc
index e8bc9cd4..cc7ae2d1 100644
--- a/chrome/installer/util/delete_tree_work_item_unittest.cc
+++ b/chrome/installer/util/delete_tree_work_item_unittest.cc
@@ -2,17 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/delete_tree_work_item.h"
+
 #include <windows.h>
 
 #include <fstream>
+#include <memory>
 
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
-#include "chrome/installer/util/delete_tree_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -73,7 +74,7 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   std::vector<base::FilePath> key_files;
-  scoped_ptr<DeleteTreeWorkItem> work_item(
+  std::unique_ptr<DeleteTreeWorkItem> work_item(
       WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
                                          key_files));
   EXPECT_TRUE(work_item->Do());
@@ -125,7 +126,7 @@
   ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
   std::vector<base::FilePath> key_files(1, file_name_delete_1);
-  scoped_ptr<DeleteTreeWorkItem> work_item(
+  std::unique_ptr<DeleteTreeWorkItem> work_item(
       WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
                                          key_files));
   EXPECT_TRUE(work_item->Do());
@@ -199,7 +200,7 @@
     ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
 
     std::vector<base::FilePath> key_paths(1, key_path);
-    scoped_ptr<DeleteTreeWorkItem> work_item(
+    std::unique_ptr<DeleteTreeWorkItem> work_item(
         WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
                                            key_paths));
 
@@ -213,9 +214,9 @@
 
     // No key paths, the deletion should succeed.
     std::vector<base::FilePath> key_paths;
-    scoped_ptr<DeleteTreeWorkItem> work_item(
+    std::unique_ptr<DeleteTreeWorkItem> work_item(
         WorkItem::CreateDeleteTreeWorkItem(dir_name_delete, temp_dir.path(),
-        key_paths));
+                                           key_paths));
 
     EXPECT_TRUE(work_item->Do());
     work_item->Rollback();
diff --git a/chrome/installer/util/firewall_manager_win.cc b/chrome/installer/util/firewall_manager_win.cc
index bec05ca3..14f387a9 100644
--- a/chrome/installer/util/firewall_manager_win.cc
+++ b/chrome/installer/util/firewall_manager_win.cc
@@ -103,17 +103,17 @@
 FirewallManager::~FirewallManager() {}
 
 // static
-scoped_ptr<FirewallManager> FirewallManager::Create(
+std::unique_ptr<FirewallManager> FirewallManager::Create(
     BrowserDistribution* dist,
     const base::FilePath& chrome_path) {
   // First try to connect to "Windows Firewall with Advanced Security" (Vista+).
-  scoped_ptr<FirewallManagerAdvancedImpl> manager(
+  std::unique_ptr<FirewallManagerAdvancedImpl> manager(
       new FirewallManagerAdvancedImpl());
   if (manager->Init(dist->GetDisplayName(), chrome_path))
     return std::move(manager);
 
   // Next try to connect to "Windows Firewall for Windows XP with SP2".
-  scoped_ptr<FirewallManagerLegacyImpl> legacy_manager(
+  std::unique_ptr<FirewallManagerLegacyImpl> legacy_manager(
       new FirewallManagerLegacyImpl());
   if (legacy_manager->Init(dist->GetDisplayName(), chrome_path))
     return std::move(legacy_manager);
diff --git a/chrome/installer/util/firewall_manager_win.h b/chrome/installer/util/firewall_manager_win.h
index 94119613..9fe837f 100644
--- a/chrome/installer/util/firewall_manager_win.h
+++ b/chrome/installer/util/firewall_manager_win.h
@@ -5,8 +5,9 @@
 #ifndef CHROME_INSTALLER_UTIL_FIREWALL_MANAGER_WIN_H_
 #define CHROME_INSTALLER_UTIL_FIREWALL_MANAGER_WIN_H_
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 
 class BrowserDistribution;
 
@@ -23,8 +24,9 @@
 
   // Creates instance of |FirewallManager|. Implementation chooses best version
   // available for current version of Windows.
-  static scoped_ptr<FirewallManager> Create(BrowserDistribution* dist,
-                                            const base::FilePath& chrome_path);
+  static std::unique_ptr<FirewallManager> Create(
+      BrowserDistribution* dist,
+      const base::FilePath& chrome_path);
 
   // Returns true if application can one ports for incoming connections without
   // triggering firewall alert. It still does not guarantee that traffic
diff --git a/chrome/installer/util/google_chrome_binaries_distribution.cc b/chrome/installer/util/google_chrome_binaries_distribution.cc
index c5640f81..4c3d6e1 100644
--- a/chrome/installer/util/google_chrome_binaries_distribution.cc
+++ b/chrome/installer/util/google_chrome_binaries_distribution.cc
@@ -19,9 +19,8 @@
 }  // namespace
 
 GoogleChromeBinariesDistribution::GoogleChromeBinariesDistribution()
-    : ChromiumBinariesDistribution(scoped_ptr<AppRegistrationData>(
-          new UpdatingAppRegistrationData(kChromeBinariesGuid))) {
-}
+    : ChromiumBinariesDistribution(std::unique_ptr<AppRegistrationData>(
+          new UpdatingAppRegistrationData(kChromeBinariesGuid))) {}
 
 base::string16 GoogleChromeBinariesDistribution::GetDisplayName() {
   return kChromeBinariesName;
diff --git a/chrome/installer/util/google_chrome_distribution.cc b/chrome/installer/util/google_chrome_distribution.cc
index d114a8b..2d7524ff 100644
--- a/chrome/installer/util/google_chrome_distribution.cc
+++ b/chrome/installer/util/google_chrome_distribution.cc
@@ -97,12 +97,11 @@
 
 GoogleChromeDistribution::GoogleChromeDistribution()
     : BrowserDistribution(CHROME_BROWSER,
-                          scoped_ptr<AppRegistrationData>(
-                              new UpdatingAppRegistrationData(kChromeGuid))) {
-}
+                          std::unique_ptr<AppRegistrationData>(
+                              new UpdatingAppRegistrationData(kChromeGuid))) {}
 
 GoogleChromeDistribution::GoogleChromeDistribution(
-    scoped_ptr<AppRegistrationData> app_reg_data)
+    std::unique_ptr<AppRegistrationData> app_reg_data)
     : BrowserDistribution(CHROME_BROWSER, std::move(app_reg_data)) {}
 
 void GoogleChromeDistribution::DoPostUninstallOperations(
@@ -253,7 +252,7 @@
   base::FilePath crash_dir;
   if (chrome::GetDefaultCrashDumpLocation(&crash_dir)) {
     crashpad::UUID client_id;
-    scoped_ptr<crashpad::CrashReportDatabase> database(
+    std::unique_ptr<crashpad::CrashReportDatabase> database(
         crashpad::CrashReportDatabase::InitializeWithoutCreating(crash_dir));
     if (database && database->GetSettings()->GetClientID(&client_id))
       result.append(L"&crash_client_id=").append(client_id.ToString16());
diff --git a/chrome/installer/util/google_chrome_distribution.h b/chrome/installer/util/google_chrome_distribution.h
index b5a0d2f..53b7268 100644
--- a/chrome/installer/util/google_chrome_distribution.h
+++ b/chrome/installer/util/google_chrome_distribution.h
@@ -80,7 +80,7 @@
   GoogleChromeDistribution();
 
   explicit GoogleChromeDistribution(
-      scoped_ptr<AppRegistrationData> app_reg_data);
+      std::unique_ptr<AppRegistrationData> app_reg_data);
 
  private:
   friend class BrowserDistribution;
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index cb62e514..773e4e2 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -23,12 +23,11 @@
 GoogleChromeDistribution::GoogleChromeDistribution()
     : BrowserDistribution(
           CHROME_BROWSER,
-          scoped_ptr<AppRegistrationData>(
-              new NonUpdatingAppRegistrationData(base::string16()))) {
-}
+          std::unique_ptr<AppRegistrationData>(
+              new NonUpdatingAppRegistrationData(base::string16()))) {}
 
 GoogleChromeDistribution::GoogleChromeDistribution(
-    scoped_ptr<AppRegistrationData> app_reg_data)
+    std::unique_ptr<AppRegistrationData> app_reg_data)
     : BrowserDistribution(CHROME_BROWSER, std::move(app_reg_data)) {}
 
 void GoogleChromeDistribution::DoPostUninstallOperations(
diff --git a/chrome/installer/util/google_chrome_sxs_distribution.cc b/chrome/installer/util/google_chrome_sxs_distribution.cc
index 471f880..e43698b23 100644
--- a/chrome/installer/util/google_chrome_sxs_distribution.cc
+++ b/chrome/installer/util/google_chrome_sxs_distribution.cc
@@ -25,9 +25,8 @@
 }  // namespace
 
 GoogleChromeSxSDistribution::GoogleChromeSxSDistribution()
-    : GoogleChromeDistribution(scoped_ptr<AppRegistrationData>(
-          new UpdatingAppRegistrationData(kChromeSxSGuid))) {
-}
+    : GoogleChromeDistribution(std::unique_ptr<AppRegistrationData>(
+          new UpdatingAppRegistrationData(kChromeSxSGuid))) {}
 
 base::string16 GoogleChromeSxSDistribution::GetBaseAppName() {
   return L"Google Chrome Canary";
diff --git a/chrome/installer/util/google_update_settings.cc b/chrome/installer/util/google_update_settings.cc
index 3e17677..5fdc0c1 100644
--- a/chrome/installer/util/google_update_settings.cc
+++ b/chrome/installer/util/google_update_settings.cc
@@ -311,14 +311,15 @@
   return (result == ERROR_SUCCESS);
 }
 
-scoped_ptr<metrics::ClientInfo> GoogleUpdateSettings::LoadMetricsClientInfo() {
+std::unique_ptr<metrics::ClientInfo>
+GoogleUpdateSettings::LoadMetricsClientInfo() {
   base::string16 client_id_16;
   if (!ReadGoogleUpdateStrKey(google_update::kRegMetricsId, &client_id_16) ||
       client_id_16.empty()) {
-    return scoped_ptr<metrics::ClientInfo>();
+    return std::unique_ptr<metrics::ClientInfo>();
   }
 
-  scoped_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
+  std::unique_ptr<metrics::ClientInfo> client_info(new metrics::ClientInfo);
   client_info->client_id = base::UTF16ToUTF8(client_id_16);
 
   base::string16 installation_date_str;
diff --git a/chrome/installer/util/google_update_settings.h b/chrome/installer/util/google_update_settings.h
index 7b2a3966..e2dc638 100644
--- a/chrome/installer/util/google_update_settings.h
+++ b/chrome/installer/util/google_update_settings.h
@@ -7,10 +7,10 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
 #include "base/version.h"
@@ -98,7 +98,7 @@
   // if-and-only-if the client_id couldn't be retrieved (failure to retrieve
   // other fields only makes them keep their default value). A non-null return
   // will NEVER contain an empty client_id field.
-  static scoped_ptr<metrics::ClientInfo> LoadMetricsClientInfo();
+  static std::unique_ptr<metrics::ClientInfo> LoadMetricsClientInfo();
 
   // Stores a backup of the metrics client info in the registry. Storing a
   // |client_info| with an empty client id will effectively void the backup.
diff --git a/chrome/installer/util/google_update_settings_unittest.cc b/chrome/installer/util/google_update_settings_unittest.cc
index 3b4cb2d..6f51af3 100644
--- a/chrome/installer/util/google_update_settings_unittest.cc
+++ b/chrome/installer/util/google_update_settings_unittest.cc
@@ -8,9 +8,10 @@
 #include <shlwapi.h>  // For SHDeleteKey.
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/base_paths.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_path_override.h"
@@ -499,7 +500,7 @@
 }
 
 TEST_F(GoogleUpdateSettingsTest, UpdateInstallStatusTest) {
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
   // Test incremental install failure
   ASSERT_TRUE(CreateApKey(work_item_list.get(), L""))
       << "Failed to create ap key.";
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index b07d1a47..c3e32d92 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -12,13 +12,13 @@
 #include <shlwapi.h>
 
 #include <algorithm>
+#include <memory>
 
 #include "base/command_line.h"
 #include "base/environment.h"
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/numerics/safe_conversions.h"
 #include "base/path_service.h"
 #include "base/process/launch.h"
@@ -361,7 +361,7 @@
 }
 
 bool InstallUtil::IsPerUserInstall(const base::FilePath& exe_path) {
-  scoped_ptr<base::Environment> env(base::Environment::Create());
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
 
   static const char kEnvProgramFilesPath[] = "CHROME_PROBED_PROGRAM_FILES_PATH";
   std::string env_program_files_path;
diff --git a/chrome/installer/util/install_util_unittest.cc b/chrome/installer/util/install_util_unittest.cc
index 15b7a46..67d1e72 100644
--- a/chrome/installer/util/install_util_unittest.cc
+++ b/chrome/installer/util/install_util_unittest.cc
@@ -49,7 +49,8 @@
   }
 
  private:
-  scoped_ptr<registry_util::RegistryOverrideManager> registry_override_manager_;
+  std::unique_ptr<registry_util::RegistryOverrideManager>
+      registry_override_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(InstallUtilTest);
 };
diff --git a/chrome/installer/util/installation_state.h b/chrome/installer/util/installation_state.h
index 5db03610..532332dc 100644
--- a/chrome/installer/util/installation_state.h
+++ b/chrome/installer/util/installation_state.h
@@ -5,12 +5,12 @@
 #ifndef CHROME_INSTALLER_UTIL_INSTALLATION_STATE_H_
 #define CHROME_INSTALLER_UTIL_INSTALLATION_STATE_H_
 
+#include <memory>
 #include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/installer/util/app_commands.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/channel_info.h"
@@ -105,8 +105,8 @@
                                  AppCommands* commands);
 
   ChannelInfo channel_;
-  scoped_ptr<Version> version_;
-  scoped_ptr<Version> old_version_;
+  std::unique_ptr<Version> version_;
+  std::unique_ptr<Version> old_version_;
   std::wstring brand_;
   std::wstring rename_cmd_;
   std::wstring oem_install_;
diff --git a/chrome/installer/util/installer_state.cc b/chrome/installer/util/installer_state.cc
index 7f4d8471..56b701d0 100644
--- a/chrome/installer/util/installer_state.cc
+++ b/chrome/installer/util/installer_state.cc
@@ -8,6 +8,7 @@
 
 #include <algorithm>
 #include <functional>
+#include <memory>
 #include <utility>
 
 #include "base/command_line.h"
@@ -16,7 +17,6 @@
 #include "base/files/file_util.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/win/registry.h"
@@ -265,7 +265,7 @@
 // returns a pointer to the product (ownership is held by this object).
 Product* InstallerState::AddProductInDirectory(
     const base::FilePath* product_dir,
-    scoped_ptr<Product>* product) {
+    std::unique_ptr<Product>* product) {
   DCHECK(product != NULL);
   DCHECK(product->get() != NULL);
   const Product& the_product = *product->get();
@@ -292,7 +292,7 @@
   return products_[products_.size() - 1];
 }
 
-Product* InstallerState::AddProduct(scoped_ptr<Product>* product) {
+Product* InstallerState::AddProduct(std::unique_ptr<Product>* product) {
   return AddProductInDirectory(NULL, product);
 }
 
@@ -305,9 +305,8 @@
     BrowserDistribution::Type distribution_type,
     const MasterPreferences& prefs,
     const InstallationState& machine_state) {
-  scoped_ptr<Product> product_ptr(
-      new Product(BrowserDistribution::GetSpecificDistribution(
-          distribution_type)));
+  std::unique_ptr<Product> product_ptr(new Product(
+      BrowserDistribution::GetSpecificDistribution(distribution_type)));
   product_ptr->InitializeFromPreferences(prefs);
 
   Product* product = AddProductInDirectory(NULL, &product_ptr);
@@ -325,7 +324,7 @@
 Product* InstallerState::AddProductFromState(
     BrowserDistribution::Type type,
     const ProductState& state) {
-  scoped_ptr<Product> product_ptr(
+  std::unique_ptr<Product> product_ptr(
       new Product(BrowserDistribution::GetSpecificDistribution(type)));
   product_ptr->InitializeFromUninstallCommand(state.uninstall_command());
 
@@ -374,7 +373,7 @@
 Version* InstallerState::GetCurrentVersion(
     const InstallationState& machine_state) const {
   DCHECK(!products_.empty());
-  scoped_ptr<Version> current_version;
+  std::unique_ptr<Version> current_version;
   // If we're doing a multi-install, the current version may be either an
   // existing multi or an existing single product that is being migrated
   // in place (i.e., Chrome).  In the latter case, there is no existing
@@ -500,7 +499,7 @@
   // Check only for the current version (i.e., the version we are upgrading
   // _from_). Later versions from pending in-use updates need not be checked
   // since the current version is guaranteed to be in use if any such are.
-  scoped_ptr<Version> current_version(GetCurrentVersion(machine_state));
+  std::unique_ptr<Version> current_version(GetCurrentVersion(machine_state));
   if (!current_version)
     return false;
   base::FilePath directory(
@@ -526,7 +525,7 @@
 
   for (size_t i = 0; i < arraysize(kChromeFilenames); ++i) {
     base::FilePath chrome_exe(target_path().Append(kChromeFilenames[i]));
-    scoped_ptr<FileVersionInfo> file_version_info(
+    std::unique_ptr<FileVersionInfo> file_version_info(
         FileVersionInfo::CreateFileVersionInfo(chrome_exe));
     if (file_version_info) {
       base::string16 version_string = file_version_info->file_version();
@@ -541,7 +540,7 @@
     Version* existing_version,
     const base::FilePath& temp_path) const {
   Version version;
-  scoped_ptr<WorkItem> item;
+  std::unique_ptr<WorkItem> item;
 
   std::set<std::string> existing_version_strings;
   existing_version_strings.insert(new_version.GetString());
@@ -672,7 +671,7 @@
     int string_resource_id,
     const std::wstring* const launch_cmd) const {
   // Use a no-rollback list since this is a best-effort deal.
-  scoped_ptr<WorkItemList> install_list(
+  std::unique_ptr<WorkItemList> install_list(
       WorkItem::CreateNoRollbackWorkItemList());
   const bool system_install = this->system_install();
   // Write the value for all products upon which we're operating.
diff --git a/chrome/installer/util/installer_state.h b/chrome/installer/util/installer_state.h
index 4791509..7e1f6887 100644
--- a/chrome/installer/util/installer_state.h
+++ b/chrome/installer/util/installer_state.h
@@ -7,6 +7,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -14,7 +15,6 @@
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/strings/string16.h"
 #include "base/version.h"
@@ -94,7 +94,7 @@
   // Returns the product that was added, or NULL if |product| is incompatible
   // with this object.  Ownership of |product| is taken by this object, while
   // ownership of the return value is not passed to the caller.
-  Product* AddProduct(scoped_ptr<Product>* product);
+  Product* AddProduct(std::unique_ptr<Product>* product);
 
   // Removes |product| from the set of products to be operated on.  The object
   // pointed to by |product| is freed.  Returns false if |product| is not
@@ -241,7 +241,7 @@
   bool CanAddProduct(const Product& product,
                      const base::FilePath* product_dir) const;
   Product* AddProductInDirectory(const base::FilePath* product_dir,
-                                 scoped_ptr<Product>* product);
+                                 std::unique_ptr<Product>* product);
   Product* AddProductFromPreferences(
       BrowserDistribution::Type distribution_type,
       const MasterPreferences& prefs,
diff --git a/chrome/installer/util/installer_state_unittest.cc b/chrome/installer/util/installer_state_unittest.cc
index 1ced49e..5576fbc0 100644
--- a/chrome/installer/util/installer_state_unittest.cc
+++ b/chrome/installer/util/installer_state_unittest.cc
@@ -476,7 +476,8 @@
   installer_state.Initialize(cmd_line, prefs, machine_state);
 
   // Is the Chrome version picked up?
-  scoped_ptr<Version> version(installer_state.GetCurrentVersion(machine_state));
+  std::unique_ptr<Version> version(
+      installer_state.GetCurrentVersion(machine_state));
   EXPECT_TRUE(version.get() != NULL);
 }
 
@@ -729,7 +730,7 @@
   static Version* high_version_;
 
   base::CommandLine cmd_line_;
-  scoped_ptr<MasterPreferences> prefs_;
+  std::unique_ptr<MasterPreferences> prefs_;
   InstallationState machine_state_;
   MockInstallerState installer_state_;
 };
diff --git a/chrome/installer/util/l10n_string_util.cc b/chrome/installer/util/l10n_string_util.cc
index 5d93814..68acc92 100644
--- a/chrome/installer/util/l10n_string_util.cc
+++ b/chrome/installer/util/l10n_string_util.cc
@@ -11,9 +11,9 @@
 
 #include <algorithm>
 #include <limits>
+#include <memory>
 
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/installer/util/language_selector.h"
@@ -93,7 +93,7 @@
   // (see the definition of full_exe_path and resource).
   DCHECK(std::numeric_limits<uint32_t>::max() > (url_path.size() * 3));
   DWORD count = static_cast<DWORD>(url_path.size() * 3);
-  scoped_ptr<wchar_t[]> url_canon(new wchar_t[count]);
+  std::unique_ptr<wchar_t[]> url_canon(new wchar_t[count]);
   HRESULT hr = ::UrlCanonicalizeW(url_path.c_str(), url_canon.get(),
                                   &count, URL_ESCAPE_UNSAFE);
   if (SUCCEEDED(hr))
diff --git a/chrome/installer/util/lzma_file_allocator_unittest.cc b/chrome/installer/util/lzma_file_allocator_unittest.cc
index 246b67e0..e790495 100644
--- a/chrome/installer/util/lzma_file_allocator_unittest.cc
+++ b/chrome/installer/util/lzma_file_allocator_unittest.cc
@@ -6,11 +6,12 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <string>
 
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
+#include "base/memory/ptr_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 class LzmaFileAllocatorTest : public testing::Test {
@@ -62,8 +63,8 @@
 }
 
 TEST_F(LzmaFileAllocatorTest, DeleteAfterCloseTest) {
-  scoped_ptr<LzmaFileAllocator> allocator =
-      make_scoped_ptr(new LzmaFileAllocator(temp_dir_.path()));
+  std::unique_ptr<LzmaFileAllocator> allocator =
+      base::WrapUnique(new LzmaFileAllocator(temp_dir_.path()));
   base::FilePath file_path = allocator->mapped_file_path_;
   ASSERT_TRUE(base::PathExists(file_path));
   allocator.reset();
diff --git a/chrome/installer/util/master_preferences.cc b/chrome/installer/util/master_preferences.cc
index 9ce24e8..c7d4d8a8 100644
--- a/chrome/installer/util/master_preferences.cc
+++ b/chrome/installer/util/master_preferences.cc
@@ -58,7 +58,7 @@
     const std::string& json_data) {
   JSONStringValueDeserializer json(json_data);
   std::string error;
-  scoped_ptr<base::Value> root(json.Deserialize(NULL, &error));
+  std::unique_ptr<base::Value> root(json.Deserialize(NULL, &error));
   if (!root.get()) {
     LOG(WARNING) << "Failed to parse master prefs file: " << error;
     return NULL;
@@ -169,7 +169,7 @@
 
   // Handle the special case of --system-level being implied by the presence of
   // the kGoogleUpdateIsMachineEnvVar environment variable.
-  scoped_ptr<base::Environment> env(base::Environment::Create());
+  std::unique_ptr<base::Environment> env(base::Environment::Create());
   if (env != NULL) {
     std::string is_machine_var;
     env->GetVar(env_vars::kGoogleUpdateIsMachineEnvVar, &is_machine_var);
@@ -302,7 +302,7 @@
 std::string MasterPreferences::ExtractPrefString(
     const std::string& name) const {
   std::string result;
-  scoped_ptr<base::Value> pref_value;
+  std::unique_ptr<base::Value> pref_value;
   if (master_dictionary_->Remove(name, &pref_value)) {
     if (!pref_value->GetAsString(&result))
       NOTREACHED();
diff --git a/chrome/installer/util/master_preferences.h b/chrome/installer/util/master_preferences.h
index afaf319..424c4df 100644
--- a/chrome/installer/util/master_preferences.h
+++ b/chrome/installer/util/master_preferences.h
@@ -8,12 +8,12 @@
 #ifndef CHROME_INSTALLER_UTIL_MASTER_PREFERENCES_H_
 #define CHROME_INSTALLER_UTIL_MASTER_PREFERENCES_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/command_line.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "build/build_config.h"
 
 namespace base {
@@ -208,7 +208,7 @@
   // copied over to profile preferences.
   std::string ExtractPrefString(const std::string& name) const;
 
-  scoped_ptr<base::DictionaryValue> master_dictionary_;
+  std::unique_ptr<base::DictionaryValue> master_dictionary_;
   base::DictionaryValue* distribution_;
   bool preferences_read_from_file_;
   bool chrome_;
diff --git a/chrome/installer/util/master_preferences_unittest.cc b/chrome/installer/util/master_preferences_unittest.cc
index fe2e141..c3e76ba 100644
--- a/chrome/installer/util/master_preferences_unittest.cc
+++ b/chrome/installer/util/master_preferences_unittest.cc
@@ -4,17 +4,19 @@
 //
 // Unit tests for master preferences related methods.
 
+#include "chrome/installer/util/master_preferences.h"
+
 #include <stddef.h>
 
+#include <memory>
+
 #include "base/files/file_util.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/stringprintf.h"
 #include "base/values.h"
 #include "chrome/common/chrome_paths.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/installer/util/master_preferences.h"
 #include "chrome/installer/util/master_preferences_constants.h"
 #include "chrome/installer/util/util_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/installer/util/module_util_win.cc b/chrome/installer/util/module_util_win.cc
index 3a8df19..2ed5513 100644
--- a/chrome/installer/util/module_util_win.cc
+++ b/chrome/installer/util/module_util_win.cc
@@ -4,11 +4,12 @@
 
 #include "chrome/installer/util/module_util_win.h"
 
+#include <memory>
+
 #include "base/base_paths.h"
 #include "base/file_version_info.h"
 #include "base/files/file.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/path_service.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
@@ -21,7 +22,7 @@
 
 // Returns the version in the current executable's version resource.
 base::string16 GetCurrentExecutableVersion() {
-  scoped_ptr<FileVersionInfo> file_version_info(
+  std::unique_ptr<FileVersionInfo> file_version_info(
       FileVersionInfo::CreateFileVersionInfoForModule(CURRENT_MODULE()));
   DCHECK(file_version_info.get());
   base::string16 version_string(file_version_info->file_version());
diff --git a/chrome/installer/util/move_tree_work_item_unittest.cc b/chrome/installer/util/move_tree_work_item_unittest.cc
index c4be1ea..8a82a800 100644
--- a/chrome/installer/util/move_tree_work_item_unittest.cc
+++ b/chrome/installer/util/move_tree_work_item_unittest.cc
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/move_tree_work_item.h"
+
 #include <windows.h>
 
 #include <fstream>
+#include <memory>
 
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/memory_mapped_file.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/installer/util/installer_util_test_common.h"
-#include "chrome/installer/util/move_tree_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -85,11 +86,8 @@
   ASSERT_FALSE(base::PathExists(to_file));
 
   // test Do()
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_dir1,
-                                       to_dir,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_dir1, to_dir, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_FALSE(base::PathExists(from_dir1));
@@ -140,11 +138,8 @@
   ASSERT_FALSE(base::PathExists(new_to_file));
 
   // test Do(), don't check for duplicates.
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_dir1,
-                                       to_dir,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_dir1, to_dir, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_FALSE(base::PathExists(from_dir1));
@@ -183,11 +178,8 @@
   ASSERT_FALSE(base::PathExists(to_file));
 
   // test Do()
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_file,
-                                       to_file,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_file, to_file, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_TRUE(base::PathExists(from_dir));
@@ -230,11 +222,8 @@
   ASSERT_TRUE(base::PathExists(to_file));
 
   // test Do()
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_file,
-                                       to_dir,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_file, to_dir, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_TRUE(base::PathExists(from_dir));
@@ -290,11 +279,8 @@
                               NULL, NULL, &si, &pi));
 
   // test Do()
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_file,
-                                       to_file,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_file, to_file, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_TRUE(base::PathExists(from_dir));
@@ -353,11 +339,8 @@
                               NULL, NULL, &si, &pi));
 
   // test Do()
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_file,
-                                       to_file,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_file, to_file, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_TRUE(work_item->Do());
 
   EXPECT_TRUE(base::PathExists(from_dir));
@@ -417,11 +400,8 @@
   EXPECT_TRUE(mapped_file.Initialize(orig_to_file));
 
   // First check that we can't do the regular Move().
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_dir1,
-                                       to_dir,
-                                       temp_to_dir_.path(),
-                                       WorkItem::ALWAYS_MOVE));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_dir1, to_dir, temp_to_dir_.path(), WorkItem::ALWAYS_MOVE));
   EXPECT_FALSE(work_item->Do());
   work_item->Rollback();
 
@@ -502,11 +482,8 @@
   ASSERT_TRUE(base::PathExists(orig_to_file));
 
   // test Do(), check for duplicates.
-  scoped_ptr<MoveTreeWorkItem> work_item(
-      WorkItem::CreateMoveTreeWorkItem(from_dir1,
-                                       to_dir,
-                                       temp_to_dir_.path(),
-                                       WorkItem::CHECK_DUPLICATES));
+  std::unique_ptr<MoveTreeWorkItem> work_item(WorkItem::CreateMoveTreeWorkItem(
+      from_dir1, to_dir, temp_to_dir_.path(), WorkItem::CHECK_DUPLICATES));
   EXPECT_TRUE(work_item->Do());
 
   // Make sure that we "moved" the files, i.e. that the source directory isn't
diff --git a/chrome/installer/util/product.h b/chrome/installer/util/product.h
index 4a39544c..e727b23 100644
--- a/chrome/installer/util/product.h
+++ b/chrome/installer/util/product.h
@@ -7,12 +7,12 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/shell_util.h"
 #include "chrome/installer/util/util_constants.h"
@@ -132,7 +132,7 @@
   };
 
   BrowserDistribution* distribution_;
-  scoped_ptr<ProductOperations> operations_;
+  std::unique_ptr<ProductOperations> operations_;
   std::set<std::wstring> options_;
 
  private:
diff --git a/chrome/installer/util/registry_key_backup.cc b/chrome/installer/util/registry_key_backup.cc
index ecc89f6c..daf9950 100644
--- a/chrome/installer/util/registry_key_backup.cc
+++ b/chrome/installer/util/registry_key_backup.cc
@@ -284,7 +284,7 @@
          wow64_access == KEY_WOW64_64KEY);
 
   RegKey key;
-  scoped_ptr<KeyData> key_data;
+  std::unique_ptr<KeyData> key_data;
 
   // Does the key exist?
   LONG result = key.Open(root, key_path, kKeyReadNoNotify | wow64_access);
diff --git a/chrome/installer/util/registry_key_backup.h b/chrome/installer/util/registry_key_backup.h
index 6d4e9f89..df4636f 100644
--- a/chrome/installer/util/registry_key_backup.h
+++ b/chrome/installer/util/registry_key_backup.h
@@ -7,8 +7,9 @@
 
 #include <windows.h>
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 
 // A container for a registry key, its values, and its subkeys.  We don't use
 // more obvious methods for various reasons:
@@ -41,7 +42,7 @@
   class KeyData;
 
   // The values and subkeys of the backed-up key.
-  scoped_ptr<KeyData> key_data_;
+  std::unique_ptr<KeyData> key_data_;
 
   DISALLOW_COPY_AND_ASSIGN(RegistryKeyBackup);
 };
diff --git a/chrome/installer/util/registry_key_backup_unittest.cc b/chrome/installer/util/registry_key_backup_unittest.cc
index 2c2c7f9b..df8ecc0 100644
--- a/chrome/installer/util/registry_key_backup_unittest.cc
+++ b/chrome/installer/util/registry_key_backup_unittest.cc
@@ -2,12 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/registry_key_backup.h"
+
 #include <windows.h>
 
+#include <memory>
+
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/registry_key_backup.h"
 #include "chrome/installer/util/registry_test_data.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
diff --git a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
index 992b837..cae95c3 100644
--- a/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
+++ b/chrome/installer/util/scoped_user_protocol_entry_unittest.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/installer/util/scoped_user_protocol_entry.h"
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/string16.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
@@ -36,14 +37,14 @@
 
   void CreateScopedUserProtocolEntryAndVerifyRegistryValue(
       const base::string16& expected_entry_value) {
-    entry_ = make_scoped_ptr(new ScopedUserProtocolEntry());
+    entry_ = base::WrapUnique(new ScopedUserProtocolEntry());
     ASSERT_TRUE(RegistryEntry(kProtocolEntryKeyPath, kProtocolEntryName,
                               expected_entry_value)
                     .ExistsInRegistry(RegistryEntry::LOOK_IN_HKCU));
   }
 
   registry_util::RegistryOverrideManager registry_overrides_manager_;
-  scoped_ptr<ScopedUserProtocolEntry> entry_;
+  std::unique_ptr<ScopedUserProtocolEntry> entry_;
 };
 
 const wchar_t ScopedUserProtocolEntryTest::kProtocolEntryKeyPath[] =
diff --git a/chrome/installer/util/set_reg_value_work_item_unittest.cc b/chrome/installer/util/set_reg_value_work_item_unittest.cc
index c85346f..598f49ce 100644
--- a/chrome/installer/util/set_reg_value_work_item_unittest.cc
+++ b/chrome/installer/util/set_reg_value_work_item_unittest.cc
@@ -2,18 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/set_reg_value_work_item.h"
+
 #include <windows.h>
 
+#include <memory>
 #include <string>
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
-#include "chrome/installer/util/set_reg_value_work_item.h"
 #include "chrome/installer/util/work_item.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -54,21 +55,15 @@
 
 // Write a new value without overwrite flag. The value should be set.
 TEST_F(SetRegValueWorkItemTest, WriteNewNonOverwrite) {
-  scoped_ptr<SetRegValueWorkItem> work_item1(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameStr,
-                                          kDataStr1,
-                                          false));
+  std::unique_ptr<SetRegValueWorkItem> work_item1(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameStr,
+                                          kDataStr1, false));
 
-  scoped_ptr<SetRegValueWorkItem> work_item2(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameDword,
-                                          kDword1,
-                                          false));
+  std::unique_ptr<SetRegValueWorkItem> work_item2(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameDword,
+                                          kDword1, false));
 
   ASSERT_TRUE(work_item1->Do());
   ASSERT_TRUE(work_item2->Do());
@@ -90,21 +85,15 @@
 
 // Write a new value with overwrite flag. The value should be set.
 TEST_F(SetRegValueWorkItemTest, WriteNewOverwrite) {
-  scoped_ptr<SetRegValueWorkItem> work_item1(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameStr,
-                                          kDataStr1,
-                                          true));
+  std::unique_ptr<SetRegValueWorkItem> work_item1(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameStr,
+                                          kDataStr1, true));
 
-  scoped_ptr<SetRegValueWorkItem> work_item2(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameDword,
-                                          kDword1,
-                                          true));
+  std::unique_ptr<SetRegValueWorkItem> work_item2(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameDword,
+                                          kDword1, true));
 
   ASSERT_TRUE(work_item1->Do());
   ASSERT_TRUE(work_item2->Do());
@@ -131,13 +120,10 @@
   // Write data to the value we are going to set.
   ASSERT_EQ(ERROR_SUCCESS, test_key_.WriteValue(kNameStr, kDataStr1));
 
-  scoped_ptr<SetRegValueWorkItem> work_item(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameStr,
-                                          kDataStr2,
-                                          false));
+  std::unique_ptr<SetRegValueWorkItem> work_item(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameStr,
+                                          kDataStr2, false));
   ASSERT_TRUE(work_item->Do());
 
   std::wstring read_out;
@@ -181,20 +167,14 @@
   ASSERT_EQ(ERROR_SUCCESS, RegSetValueEx(test_key_.Handle(), kNameEmpty, NULL,
                                          REG_SZ, NULL, 0));
 
-  scoped_ptr<SetRegValueWorkItem> work_item1(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameStr,
-                                          kDataStr2,
-                                          true));
-  scoped_ptr<SetRegValueWorkItem> work_item2(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameEmpty,
-                                          kDataStr2,
-                                          true));
+  std::unique_ptr<SetRegValueWorkItem> work_item1(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameStr,
+                                          kDataStr2, true));
+  std::unique_ptr<SetRegValueWorkItem> work_item2(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameEmpty,
+                                          kDataStr2, true));
 
   ASSERT_TRUE(work_item1->Do());
   ASSERT_TRUE(work_item2->Do());
@@ -222,13 +202,10 @@
   // Now test REG_DWORD value.
   // Write data to the value we are going to set.
   ASSERT_EQ(ERROR_SUCCESS, test_key_.WriteValue(kNameDword, kDword1));
-  scoped_ptr<SetRegValueWorkItem> work_item3(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          kTestKey,
-                                          WorkItem::kWow64Default,
-                                          kNameDword,
-                                          kDword2,
-                                          true));
+  std::unique_ptr<SetRegValueWorkItem> work_item3(
+      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER, kTestKey,
+                                          WorkItem::kWow64Default, kNameDword,
+                                          kDword2, true));
   ASSERT_TRUE(work_item3->Do());
 
   DWORD read_dword;
@@ -247,13 +224,10 @@
   non_existing.append(&base::FilePath::kSeparators[0], 1);
   non_existing.append(L"NonExistingKey");
 
-  scoped_ptr<SetRegValueWorkItem> work_item(
-      WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
-                                          non_existing.c_str(),
-                                          WorkItem::kWow64Default,
-                                          kNameStr,
-                                          kDataStr1,
-                                          false));
+  std::unique_ptr<SetRegValueWorkItem> work_item(
+      WorkItem::CreateSetRegValueWorkItem(
+          HKEY_CURRENT_USER, non_existing.c_str(), WorkItem::kWow64Default,
+          kNameStr, kDataStr1, false));
   EXPECT_FALSE(work_item->Do());
 
   work_item.reset(WorkItem::CreateSetRegValueWorkItem(HKEY_CURRENT_USER,
@@ -286,12 +260,9 @@
 
   int callback_invocation_count = 0;
 
-  scoped_ptr<SetRegValueWorkItem> work_item(
+  std::unique_ptr<SetRegValueWorkItem> work_item(
       WorkItem::CreateSetRegValueWorkItem(
-          HKEY_CURRENT_USER,
-          kTestKey,
-          WorkItem::kWow64Default,
-          kNameStr,
+          HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr,
           base::Bind(&VerifyPreviousValueAndReplace, &callback_invocation_count,
                      kDataStr1, kDataStr2)));
 
@@ -321,12 +292,9 @@
 TEST_F(SetRegValueWorkItemTest, ModifyNonExistingWithCallback) {
   int callback_invocation_count = 0;
 
-  scoped_ptr<SetRegValueWorkItem> work_item(
+  std::unique_ptr<SetRegValueWorkItem> work_item(
       WorkItem::CreateSetRegValueWorkItem(
-          HKEY_CURRENT_USER,
-          kTestKey,
-          WorkItem::kWow64Default,
-          kNameStr,
+          HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr,
           base::Bind(&VerifyPreviousValueAndReplace, &callback_invocation_count,
                      L"", kDataStr1)));
 
@@ -355,12 +323,9 @@
 
   int callback_invocation_count = 0;
 
-  scoped_ptr<SetRegValueWorkItem> work_item(
+  std::unique_ptr<SetRegValueWorkItem> work_item(
       WorkItem::CreateSetRegValueWorkItem(
-          HKEY_CURRENT_USER,
-          kTestKey,
-          WorkItem::kWow64Default,
-          kNameStr,
+          HKEY_CURRENT_USER, kTestKey, WorkItem::kWow64Default, kNameStr,
           base::Bind(&VerifyPreviousValueAndReplace, &callback_invocation_count,
                      L"", kDataStr1)));
 
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index 493437069..202d871 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -14,6 +14,7 @@
 #include <shobjidl.h>
 
 #include <limits>
+#include <memory>
 #include <string>
 
 #include "base/bind.h"
@@ -25,7 +26,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/md5.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/path_service.h"
@@ -540,7 +540,7 @@
   base::string16 key_name(ShellUtil::kRegClasses);
   key_name.push_back(base::FilePath::kSeparators[0]);
   key_name.append(ext);
-  scoped_ptr<RegistryEntry> default_association(
+  std::unique_ptr<RegistryEntry> default_association(
       new RegistryEntry(key_name, prog_id));
   if (overwrite_existing ||
       !default_association->KeyExistsInRegistry(RegistryEntry::LOOK_IN_HKCU)) {
@@ -2334,7 +2334,7 @@
 // static
 bool ShellUtil::AddRegistryEntries(HKEY root,
                                    const ScopedVector<RegistryEntry>& entries) {
-  scoped_ptr<WorkItemList> items(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItemList> items(WorkItem::CreateWorkItemList());
 
   for (ScopedVector<RegistryEntry>::const_iterator itr = entries.begin();
        itr != entries.end(); ++itr)
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 2ae2309..b46b755a 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <stddef.h>
 
+#include <memory>
 #include <vector>
 
 #include "base/base_paths.h"
@@ -17,7 +18,6 @@
 #include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/md5.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/synchronization/cancellation_flag.h"
@@ -190,7 +190,7 @@
   }
 
   BrowserDistribution* dist_;
-  scoped_ptr<installer::Product> product_;
+  std::unique_ptr<installer::Product> product_;
 
   // A ShellUtil::ShortcutProperties object with common properties set already.
   ShellUtil::ShortcutProperties test_properties_;
@@ -202,11 +202,11 @@
   base::ScopedTempDir fake_default_user_quick_launch_;
   base::ScopedTempDir fake_start_menu_;
   base::ScopedTempDir fake_common_start_menu_;
-  scoped_ptr<base::ScopedPathOverride> user_desktop_override_;
-  scoped_ptr<base::ScopedPathOverride> common_desktop_override_;
-  scoped_ptr<base::ScopedPathOverride> user_quick_launch_override_;
-  scoped_ptr<base::ScopedPathOverride> start_menu_override_;
-  scoped_ptr<base::ScopedPathOverride> common_start_menu_override_;
+  std::unique_ptr<base::ScopedPathOverride> user_desktop_override_;
+  std::unique_ptr<base::ScopedPathOverride> common_desktop_override_;
+  std::unique_ptr<base::ScopedPathOverride> user_quick_launch_override_;
+  std::unique_ptr<base::ScopedPathOverride> start_menu_override_;
+  std::unique_ptr<base::ScopedPathOverride> common_start_menu_override_;
 
   base::FilePath chrome_exe_;
   base::FilePath manganese_exe_;
diff --git a/chrome/installer/util/uninstall_metrics.cc b/chrome/installer/util/uninstall_metrics.cc
index 606b132d..3be41c4 100644
--- a/chrome/installer/util/uninstall_metrics.cc
+++ b/chrome/installer/util/uninstall_metrics.cc
@@ -4,12 +4,12 @@
 
 #include "chrome/installer/util/uninstall_metrics.h"
 
+#include <memory>
 #include <string>
 
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
 #include "base/logging.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/installer/util/util_constants.h"
@@ -78,7 +78,7 @@
   JSONFileValueDeserializer json_deserializer(file_path);
 
   std::string json_error_string;
-  scoped_ptr<base::Value> root = json_deserializer.Deserialize(NULL, NULL);
+  std::unique_ptr<base::Value> root = json_deserializer.Deserialize(NULL, NULL);
   if (!root.get())
     return false;
 
diff --git a/chrome/installer/util/uninstall_metrics_unittest.cc b/chrome/installer/util/uninstall_metrics_unittest.cc
index 72b891f1..53359f9 100644
--- a/chrome/installer/util/uninstall_metrics_unittest.cc
+++ b/chrome/installer/util/uninstall_metrics_unittest.cc
@@ -4,10 +4,10 @@
 
 #include "chrome/installer/util/uninstall_metrics.h"
 
+#include <memory>
 #include <string>
 
 #include "base/json/json_string_value_serializer.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string16.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -46,7 +46,7 @@
   JSONStringValueDeserializer json_deserializer(pref_string);
   std::string error_message;
 
-  scoped_ptr<base::Value> root =
+  std::unique_ptr<base::Value> root =
       json_deserializer.Deserialize(NULL, &error_message);
   ASSERT_TRUE(root.get());
   base::string16 uninstall_metrics_string;
diff --git a/chrome/installer/util/work_item_list.h b/chrome/installer/util/work_item_list.h
index 62351b8..983ad0c5 100644
--- a/chrome/installer/util/work_item_list.h
+++ b/chrome/installer/util/work_item_list.h
@@ -9,11 +9,11 @@
 #include <stdint.h>
 
 #include <list>
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/callback_forward.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/installer/util/work_item.h"
 
 namespace base {
diff --git a/chrome/installer/util/work_item_list_unittest.cc b/chrome/installer/util/work_item_list_unittest.cc
index 1a2eb3d..c0592f9 100644
--- a/chrome/installer/util/work_item_list_unittest.cc
+++ b/chrome/installer/util/work_item_list_unittest.cc
@@ -2,18 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/installer/util/work_item_list.h"
+
 #include <windows.h>
 
+#include <memory>
+
 #include "base/base_paths.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/strings/string_util.h"
 #include "base/test/test_reg_util_win.h"
 #include "base/win/registry.h"
 #include "chrome/installer/util/conditional_work_item_list.h"
 #include "chrome/installer/util/work_item.h"
-#include "chrome/installer/util/work_item_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 using base::win::RegKey;
@@ -41,8 +43,8 @@
 
 // Execute a WorkItem list successfully and then rollback.
 TEST_F(WorkItemListTest, ExecutionSuccess) {
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
-  scoped_ptr<WorkItem> work_item;
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItem> work_item;
 
   base::FilePath top_dir_to_create(temp_dir_.path());
   top_dir_to_create = top_dir_to_create.AppendASCII("a");
@@ -98,8 +100,8 @@
 
 // Execute a WorkItem list. Fail in the middle. Rollback what has been done.
 TEST_F(WorkItemListTest, ExecutionFailAndRollback) {
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
-  scoped_ptr<WorkItem> work_item;
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItem> work_item;
 
   base::FilePath top_dir_to_create(temp_dir_.path());
   top_dir_to_create = top_dir_to_create.AppendASCII("a");
@@ -161,8 +163,8 @@
 }
 
 TEST_F(WorkItemListTest, ConditionalExecutionSuccess) {
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
-  scoped_ptr<WorkItem> work_item;
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItem> work_item;
 
   base::FilePath top_dir_to_create(temp_dir_.path());
   top_dir_to_create = top_dir_to_create.AppendASCII("a");
@@ -174,7 +176,7 @@
       WorkItem::CreateCreateDirWorkItem(dir_to_create)));
   work_item_list->AddWorkItem(work_item.release());
 
-  scoped_ptr<WorkItemList> conditional_work_item_list(
+  std::unique_ptr<WorkItemList> conditional_work_item_list(
       WorkItem::CreateConditionalWorkItemList(
           new ConditionRunIfFileExists(dir_to_create)));
 
@@ -222,8 +224,8 @@
 }
 
 TEST_F(WorkItemListTest, ConditionalExecutionConditionFailure) {
-  scoped_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
-  scoped_ptr<WorkItem> work_item;
+  std::unique_ptr<WorkItemList> work_item_list(WorkItem::CreateWorkItemList());
+  std::unique_ptr<WorkItem> work_item;
 
   base::FilePath top_dir_to_create(temp_dir_.path());
   top_dir_to_create = top_dir_to_create.AppendASCII("a");
@@ -235,7 +237,7 @@
       WorkItem::CreateCreateDirWorkItem(dir_to_create)));
   work_item_list->AddWorkItem(work_item.release());
 
-  scoped_ptr<WorkItemList> conditional_work_item_list(
+  std::unique_ptr<WorkItemList> conditional_work_item_list(
       WorkItem::CreateConditionalWorkItemList(
           new ConditionRunIfFileExists(dir_to_create.AppendASCII("c"))));
 
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 24272b7..e8e59bc 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1130,6 +1130,7 @@
     } else {
       sources -= [
         "../browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc",
+        "../browser/extensions/api/webrtc_logging_private/webrtc_event_log_apitest.cc",
         "../browser/extensions/api/webrtc_logging_private/webrtc_logging_private_apitest.cc",
         "../browser/media/chrome_webrtc_apprtc_browsertest.cc",
         "../browser/media/chrome_webrtc_audio_quality_browsertest.cc",
diff --git a/chrome/test/data/webui/net_internals/log_util.js b/chrome/test/data/webui/net_internals/log_util.js
index 8a5e50c..3dfdfcc 100644
--- a/chrome/test/data/webui/net_internals/log_util.js
+++ b/chrome/test/data/webui/net_internals/log_util.js
@@ -182,7 +182,7 @@
     bandwidth: true,
     chromeos: false
   };
-  NetInternalsTest.checkTabHandleVisibility(tabVisibilityState, false);
+  NetInternalsTest.checkTabLinkVisibility(tabVisibilityState, false);
 }
 
 /**
@@ -211,7 +211,7 @@
     bandwidth: false,
     chromeos: false
   };
-  NetInternalsTest.checkTabHandleVisibility(tabVisibilityState, false);
+  NetInternalsTest.checkTabLinkVisibility(tabVisibilityState, false);
 }
 
 function checkPrivacyStripping(expectedValue) {
diff --git a/chrome/test/data/webui/net_internals/main.js b/chrome/test/data/webui/net_internals/main.js
index 23c8ac3..9796cdc 100644
--- a/chrome/test/data/webui/net_internals/main.js
+++ b/chrome/test/data/webui/net_internals/main.js
@@ -41,7 +41,7 @@
     chromeos: cr.isChromeOS
   };
 
-  NetInternalsTest.checkTabHandleVisibility(tabVisibilityState, true);
+  NetInternalsTest.checkTabLinkVisibility(tabVisibilityState, true);
 
   testDone();
 });
diff --git a/chrome/test/data/webui/net_internals/net_internals_test.js b/chrome/test/data/webui/net_internals/net_internals_test.js
index 640c65b..53ae7e2 100644
--- a/chrome/test/data/webui/net_internals/net_internals_test.js
+++ b/chrome/test/data/webui/net_internals/net_internals_test.js
@@ -250,14 +250,14 @@
   NetInternalsTest.getTab = function(tabId) {
     var tabSwitcher = MainView.getInstance().tabSwitcher();
     var view = tabSwitcher.getTabView(tabId);
-    var menuItem = tabSwitcher.getMenuItemNode_(tabId);
+    var tabLink = tabSwitcher.tabIdToLink_[tabId];
 
     assertNotEquals(view, undefined, tabId + ' does not exist.');
-    assertNotEquals(menuItem, undefined, tabId + ' does not exist.');
+    assertNotEquals(tabLink, undefined, tabId + ' does not exist.');
 
     return {
       view: view,
-      menuItem: menuItem,
+      tabLink: tabLink,
     };
   };
 
@@ -271,14 +271,14 @@
   };
 
   /**
-   * Returns true if the specified tab's handle is visible, false otherwise.
-   * Asserts if the handle can't be found.
+   * Returns true if the specified tab's link is visible, false otherwise.
+   * Asserts if the link can't be found.
    * @param {string}: tabId Id of the tab to check.
-   * @return {bool} Whether or not the tab's handle is visible.
+   * @return {bool} Whether or not the tab's link is visible.
    */
-  NetInternalsTest.tabHandleIsVisible = function(tabId) {
-    var tabHandleNode = NetInternalsTest.getTab(tabId).menuItem;
-    return NetInternalsTest.nodeIsVisible(tabHandleNode);
+  NetInternalsTest.tabLinkIsVisible = function(tabId) {
+    var tabLink = NetInternalsTest.getTab(tabId).tabLink;
+    return NetInternalsTest.nodeIsVisible(tabLink);
   };
 
   /**
@@ -297,13 +297,12 @@
    */
   NetInternalsTest.getTabId = function(hash) {
     /**
-     * Map of tab handle names to location hashes.  Since the text fixture
-     * must be runnable independent of net-internals, for generating the
-     * test's cc files, must be careful to only create this map while a test
-     * is running.
+     * Map of tab ids to location hashes.  Since the text fixture must be
+     * runnable independent of net-internals, for generating the test's cc
+     * files, must be careful to only create this map while a test is running.
      * @type {object.<string, string>}
      */
-    var hashToTabHandleIdMap = {
+    var hashToTabIdMap = {
       capture: CaptureView.TAB_ID,
       export: ExportView.TAB_ID,
       import: ImportView.TAB_ID,
@@ -324,9 +323,9 @@
       chromeos: CrosView.TAB_ID
     };
 
-    assertEquals(typeof hashToTabHandleIdMap[hash], 'string',
+    assertEquals(typeof hashToTabIdMap[hash], 'string',
                  'Invalid tab anchor: ' + hash);
-    var tabId = hashToTabHandleIdMap[hash];
+    var tabId = hashToTabIdMap[hash];
     assertEquals('object', typeof NetInternalsTest.getTab(tabId),
                  'Invalid tab: ' + tabId);
     return tabId;
@@ -339,18 +338,24 @@
   NetInternalsTest.switchToView = function(hash) {
     var tabId = NetInternalsTest.getTabId(hash);
 
-    // Make sure the tab handle is visible, as we only simulate normal usage.
-    expectTrue(NetInternalsTest.tabHandleIsVisible(tabId),
-               tabId + ' does not have a visible tab handle.');
-    var tabHandleNode = NetInternalsTest.getTab(tabId).menuItem;
+    // Make sure the tab link is visible, as we only simulate normal usage.
+    expectTrue(NetInternalsTest.tabLinkIsVisible(tabId),
+               tabId + ' does not have a visible tab link.');
+    var tabLinkNode = NetInternalsTest.getTab(tabId).tabLink;
 
-    // Simulate selecting the menuitem.
-    tabHandleNode.selected = true;
-    tabHandleNode.parentNode.onchange();
+    // Simulate a left click on the link.
+    var mouseEvent = document.createEvent('MouseEvents');
+    mouseEvent.initMouseEvent('click', true, true, window, 1, 0, 0, 0, 0, false,
+                              false, false, false, 0, null);
+    tabLinkNode.dispatchEvent(mouseEvent);
 
     // Make sure the hash changed.
     assertEquals('#' + hash, document.location.hash);
 
+    // Run the onhashchange function, so can test the resulting state.
+    // Otherwise, the method won't trigger synchronously.
+    window.onhashchange();
+
     // Make sure only the specified tab is visible.
     var tabSwitcher = MainView.getInstance().tabSwitcher();
     var tabIdToView = tabSwitcher.getAllTabViews();
@@ -362,17 +367,17 @@
   };
 
   /**
-   * Checks the visibility of all tab handles against expected values.
+   * Checks the visibility of all tab links against expected values.
    * @param {object.<string, bool>}: tabVisibilityState Object with a an entry
    *     for each tab's hash, and a bool indicating if it should be visible or
    *     not.
    * @param {bool+}: tourTabs True if tabs expected to be visible should should
    *     each be navigated to as well.
    */
-  NetInternalsTest.checkTabHandleVisibility = function(tabVisibilityState,
-                                                       tourTabs) {
-    // The currently active tab should have a handle that is visible.
-    expectTrue(NetInternalsTest.tabHandleIsVisible(
+  NetInternalsTest.checkTabLinkVisibility = function(tabVisibilityState,
+                                                     tourTabs) {
+    // The currently active tab should have a link that is visible.
+    expectTrue(NetInternalsTest.tabLinkIsVisible(
                    NetInternalsTest.getActiveTabId()));
 
     // Check visibility state of all tabs.
@@ -382,7 +387,7 @@
       assertEquals('object', typeof NetInternalsTest.getTab(tabId),
                    'Invalid tab: ' + tabId);
       expectEquals(tabVisibilityState[hash],
-                   NetInternalsTest.tabHandleIsVisible(tabId),
+                   NetInternalsTest.tabLinkIsVisible(tabId),
                    tabId + ' visibility state is unexpected.');
       if (tourTabs && tabVisibilityState[hash])
         NetInternalsTest.switchToView(hash);
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index dc061b66..222ffd7 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -1164,7 +1164,13 @@
 
 TEST_PPAPI_NACL(TrueTypeFont)
 
-TEST_PPAPI_NACL(VideoDecoder)
+// TODO(crbug.com/602875), TODO(crbug.com/602876) Flaky on Win and CrOS.
+#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#define MAYBE_VideoDecoder DISABLED_VideoDecoder
+#else
+#define MAYBE_VideoDecoder VideoDecoder
+#endif
+TEST_PPAPI_NACL(MAYBE_VideoDecoder)
 
 TEST_PPAPI_NACL(VideoEncoder)
 
diff --git a/components/cronet/histogram_manager.cc b/components/cronet/histogram_manager.cc
index 4ec3adf..bb2ced0 100644
--- a/components/cronet/histogram_manager.cc
+++ b/components/cronet/histogram_manager.cc
@@ -53,18 +53,21 @@
 }
 
 bool HistogramManager::GetDeltas(std::vector<uint8_t>* data) {
-  // Clear the protobuf between calls.
-  uma_proto_.Clear();
-  // "false" to StatisticsRecorder::begin() indicates to *not* include
-  // histograms held in persistent storage on the assumption that they will be
-  // visible to the recipient through other means.
-  histogram_snapshot_manager_.PrepareDeltas(
-      base::StatisticsRecorder::begin(false), base::StatisticsRecorder::end(),
-      base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
-  int32_t data_size = uma_proto_.ByteSize();
-  data->resize(data_size);
-  if (uma_proto_.SerializeToArray(&(*data)[0], data_size))
-    return true;
+  if (get_deltas_lock_.Try()) {
+    base::AutoLock lock(get_deltas_lock_, base::AutoLock::AlreadyAcquired());
+    // Clear the protobuf between calls.
+    uma_proto_.Clear();
+    // "false" to StatisticsRecorder::begin() indicates to *not* include
+    // histograms held in persistent storage on the assumption that they will be
+    // visible to the recipient through other means.
+    histogram_snapshot_manager_.PrepareDeltas(
+        base::StatisticsRecorder::begin(false), base::StatisticsRecorder::end(),
+        base::Histogram::kNoFlags, base::Histogram::kUmaTargetedHistogramFlag);
+    int32_t data_size = uma_proto_.ByteSize();
+    data->resize(data_size);
+    if (uma_proto_.SerializeToArray(&(*data)[0], data_size))
+      return true;
+  }
   data->clear();
   return false;
 }
diff --git a/components/cronet/histogram_manager.h b/components/cronet/histogram_manager.h
index e4305e7..4c34ceb8 100644
--- a/components/cronet/histogram_manager.h
+++ b/components/cronet/histogram_manager.h
@@ -15,13 +15,14 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/metrics/histogram_flattener.h"
 #include "base/metrics/histogram_snapshot_manager.h"
+#include "base/synchronization/lock.h"
 #include "components/metrics/proto/chrome_user_metrics_extension.pb.h"
 
 namespace cronet {
 
 // A HistogramManager instance is created by the app. It is the central
 // controller for the acquisition of log data, and recording deltas for
-// transmission to an external server.
+// transmission to an external server. Public APIs are all thread-safe.
 class HistogramManager : public base::HistogramFlattener {
  public:
   HistogramManager();
@@ -52,6 +53,10 @@
   // Stores the protocol buffer representation for this log.
   metrics::ChromeUserMetricsExtension uma_proto_;
 
+  // Should be acquired whenever GetDeltas() is executing to maintain
+  // thread-safety.
+  base::Lock get_deltas_lock_;
+
   DISALLOW_COPY_AND_ASSIGN(HistogramManager);
 };
 
diff --git a/components/profile_service/BUILD.gn b/components/profile_service/BUILD.gn
index f6e6a21..6856e16 100644
--- a/components/profile_service/BUILD.gn
+++ b/components/profile_service/BUILD.gn
@@ -3,6 +3,7 @@
 # found in the LICENSE file.
 
 import("//mojo/public/mojo_application.gni")
+import("//mojo/public/mojo_application_manifest.gni")
 
 source_set("lib") {
   sources = [
@@ -30,4 +31,13 @@
     "//services/tracing/public/cpp",
     "//url",
   ]
+
+  data_deps = [
+    ":manifest",
+  ]
+}
+
+mojo_application_manifest("manifest") {
+  application_name = "profile"
+  source = "manifest.json"
 }
diff --git a/components/profile_service/manifest.json b/components/profile_service/manifest.json
new file mode 100644
index 0000000..2f7d94e
--- /dev/null
+++ b/components/profile_service/manifest.json
@@ -0,0 +1,11 @@
+{
+  "manifest_version": 1,
+  "name": "mojo:profile",
+  "process-group": "browser",
+  "display_name": "Profile",
+  "capabilities": {
+    "required": {
+      "mojo:tracing": { "interfaces": [ "*" ] }
+    }
+  }
+}
diff --git a/components/profile_service/profile_service.gyp b/components/profile_service/profile_service.gyp
index da787ac..be182f2 100644
--- a/components/profile_service/profile_service.gyp
+++ b/components/profile_service/profile_service.gyp
@@ -26,6 +26,7 @@
         'user_id_map.h',
       ],
       'dependencies': [
+        'profile_app_manifest',
         'profile_service_bindings',
         '../../base/base.gyp:base',
         '../../components/filesystem/filesystem.gyp:filesystem_lib',
@@ -64,6 +65,31 @@
       'includes': [
         '../../mojo/mojom_bindings_generator_explicit.gypi',
       ],
-    }
+    },
+    {
+      'target_name': 'profile_service_public_lib',
+      'type': 'static_library',
+      'sources': [
+        'public/cpp/constants.cc',
+        'public/cpp/constants.h',
+      ],
+      'include_dirs': [
+        '../..',
+      ],
+    },
+    {
+      # GN version: //components/profile_service:manifest
+      'target_name': 'profile_app_manifest',
+      'type': 'none',
+      'variables': {
+        'application_type': 'mojo',
+        'application_name': 'profile',
+        'source_manifest': '<(DEPTH)/components/profile_service/manifest.json',
+      },
+      'includes': [
+        '../../mojo/public/mojo_application_manifest.gypi',
+      ],
+      'hard_dependency': 1,
+    },
   ],
 }
diff --git a/components/profile_service/public/cpp/BUILD.gn b/components/profile_service/public/cpp/BUILD.gn
new file mode 100644
index 0000000..f341a18b
--- /dev/null
+++ b/components/profile_service/public/cpp/BUILD.gn
@@ -0,0 +1,10 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+source_set("cpp") {
+  sources = [
+    "constants.cc",
+    "constants.h",
+  ]
+}
diff --git a/components/profile_service/public/cpp/constants.cc b/components/profile_service/public/cpp/constants.cc
new file mode 100644
index 0000000..b2ddc1c
--- /dev/null
+++ b/components/profile_service/public/cpp/constants.cc
@@ -0,0 +1,11 @@
+// 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/profile_service/public/cpp/constants.h"
+
+namespace profile {
+
+const char kProfileMojoApplicationName[] = "mojo:profile";
+
+}  // namespace profile
diff --git a/components/profile_service/public/cpp/constants.h b/components/profile_service/public/cpp/constants.h
new file mode 100644
index 0000000..9f201d2
--- /dev/null
+++ b/components/profile_service/public/cpp/constants.h
@@ -0,0 +1,14 @@
+// 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 COMPONENTS_PROFILE_SERVICE_PUBLIC_CPP_CONSTANTS_H_
+#define COMPONENTS_PROFILE_SERVICE_PUBLIC_CPP_CONSTANTS_H_
+
+namespace profile {
+
+extern const char kProfileMojoApplicationName[];
+
+}  // namespace profile
+
+#endif  // COMPONENTS_PROFILE_SERVICE_PUBLIC_CPP_CONSTANTS_H_
diff --git a/content/DEPS b/content/DEPS
index 1d6f952..f5efa16c 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -81,6 +81,7 @@
   "+ui/events",
   "+ui/gfx",
   "+ui/gl",
+  "+ui/latency_info",
   "+ui/native_theme",
   "+ui/ozone/public",
   "+ui/resources/grit/ui_resources.h",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 66c0537..2c33ce0 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -36,6 +36,7 @@
     "//components/leveldb:lib",
     "//components/mime_util",
     "//components/profile_service:lib",
+    "//components/profile_service/public/cpp",
     "//components/scheduler:common",
     "//components/tracing",
     "//components/tracing:startup_tracing",
diff --git a/content/browser/android/in_process/synchronous_input_event_filter.cc b/content/browser/android/in_process/synchronous_input_event_filter.cc
index b4d9f7f..ff378b2 100644
--- a/content/browser/android/in_process/synchronous_input_event_filter.cc
+++ b/content/browser/android/in_process/synchronous_input_event_filter.cc
@@ -9,7 +9,7 @@
 #include "content/browser/android/in_process/synchronous_compositor_registry_in_proc.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/events/blink/synchronous_input_handler_proxy.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebInputEvent;
 
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc
index c8f7b145..0c57b56c 100644
--- a/content/browser/browser_context.cc
+++ b/content/browser/browser_context.cc
@@ -8,17 +8,25 @@
 #include <stdint.h>
 #include <algorithm>
 #include <limits>
+#include <memory>
 #include <utility>
+#include <vector>
 
+#include "base/command_line.h"
 #include "base/guid.h"
 #include "base/lazy_instance.h"
+#include "base/macros.h"
 #include "base/rand_util.h"
 #include "build/build_config.h"
+#include "components/profile_service/profile_app.h"
+#include "components/profile_service/public/cpp/constants.h"
 #include "components/profile_service/user_id_map.h"
 #include "content/browser/download/download_manager_impl.h"
 #include "content/browser/fileapi/chrome_blob_storage_context.h"
 #include "content/browser/indexed_db/indexed_db_context_impl.h"
 #include "content/browser/loader/resource_dispatcher_host_impl.h"
+#include "content/browser/mojo/browser_shell_connection.h"
+#include "content/browser/mojo/constants.h"
 #include "content/browser/push_messaging/push_messaging_router.h"
 #include "content/browser/storage_partition_impl_map.h"
 #include "content/common/child_process_host_impl.h"
@@ -26,11 +34,16 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/site_instance.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/mojo_shell_connection.h"
 #include "net/cookies/cookie_store.h"
 #include "net/ssl/channel_id_service.h"
 #include "net/ssl/channel_id_store.h"
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_context_getter.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
 #include "storage/browser/database/database_tracker.h"
 #include "storage/browser/fileapi/external_mount_points.h"
 
@@ -47,9 +60,9 @@
 
 // Key names on BrowserContext.
 const char kDownloadManagerKeyName[] = "download_manager";
-const char kStoragePartitionMapKeyName[] = "content_storage_partition_map";
-
+const char kMojoShellConnection[] = "mojo-shell-connection";
 const char kMojoWasInitialized[] = "mojo-was-initialized";
+const char kStoragePartitionMapKeyName[] = "content_storage_partition_map";
 
 #if defined(OS_CHROMEOS)
 const char kMountPointsKey[] = "mount_points";
@@ -110,6 +123,25 @@
   context->SetUserData(kDownloadManagerKeyName, download_manager);
 }
 
+class BrowserContextShellConnectionHolder
+    : public base::SupportsUserData::Data {
+ public:
+  BrowserContextShellConnectionHolder(
+      std::unique_ptr<mojo::Connection> connection,
+      mojo::shell::mojom::ShellClientRequest request)
+      : root_connection_(std::move(connection)),
+        shell_connection_(new BrowserShellConnection(std::move(request))) {}
+  ~BrowserContextShellConnectionHolder() override {}
+
+  BrowserShellConnection* shell_connection() { return shell_connection_.get(); }
+
+ private:
+  std::unique_ptr<mojo::Connection> root_connection_;
+  std::unique_ptr<BrowserShellConnection> shell_connection_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserContextShellConnectionHolder);
+};
+
 }  // namespace
 
 // static
@@ -330,6 +362,7 @@
   SetDownloadManager(browser_context, download_manager);
 }
 
+// static
 void BrowserContext::Initialize(
     BrowserContext* browser_context,
     const base::FilePath& path) {
@@ -344,8 +377,47 @@
   profile::AssociateMojoUserIDWithProfileDir(new_id, path);
   browser_context->SetUserData(kMojoWasInitialized,
                                new base::SupportsUserData::Data);
+
+  MojoShellConnection* shell = MojoShellConnection::Get();
+  if (shell) {
+    // NOTE: Many unit tests create a TestBrowserContext without initializing
+    // Mojo or the global Mojo shell connection.
+
+    mojo::shell::mojom::ShellClientPtr shell_client;
+    mojo::shell::mojom::ShellClientRequest shell_client_request =
+        mojo::GetProxy(&shell_client);
+
+    mojo::shell::mojom::PIDReceiverPtr pid_receiver;
+    mojo::Connector::ConnectParams params(
+        mojo::Identity(kBrowserMojoApplicationName, new_id));
+    params.set_client_process_connection(std::move(shell_client),
+                                         mojo::GetProxy(&pid_receiver));
+    pid_receiver->SetPID(base::GetCurrentProcId());
+
+    BrowserContextShellConnectionHolder* connection_holder =
+        new BrowserContextShellConnectionHolder(
+          shell->GetConnector()->Connect(&params),
+          std::move(shell_client_request));
+    browser_context->SetUserData(kMojoShellConnection, connection_holder);
+
+    BrowserShellConnection* connection = connection_holder->shell_connection();
+
+    // New embedded application factories should be added to |connection| here.
+
+    if (base::CommandLine::ForCurrentProcess()->HasSwitch(
+            switches::kMojoLocalStorage)) {
+      connection->AddEmbeddedApplication(
+          profile::kProfileMojoApplicationName,
+          base::Bind(
+              &profile::CreateProfileApp,
+              BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE),
+              BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)),
+          nullptr);
+    }
+  }
 }
 
+// static
 const std::string& BrowserContext::GetMojoUserIdFor(
     BrowserContext* browser_context) {
   CHECK(browser_context->GetUserData(kMojoWasInitialized))
@@ -361,6 +433,17 @@
   return it->second;
 }
 
+// static
+mojo::Connector* BrowserContext::GetMojoConnectorFor(
+    BrowserContext* browser_context) {
+  BrowserContextShellConnectionHolder* connection_holder =
+      static_cast<BrowserContextShellConnectionHolder*>(
+          browser_context->GetUserData(kMojoShellConnection));
+  if (!connection_holder)
+    return nullptr;
+  return connection_holder->shell_connection()->GetConnector();
+}
+
 BrowserContext::~BrowserContext() {
   CHECK(GetUserData(kMojoWasInitialized))
       << "Attempting to destroy a BrowserContext that never called "
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 534be27..5c449e5 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -1173,8 +1173,7 @@
   mojo_ipc_support_.reset(new IPC::ScopedIPCSupport(
       BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO)
           ->task_runner()));
-  mojo_shell_context_.reset(new MojoShellContext(file_thread_->task_runner(),
-                                                 db_thread_->task_runner()));
+  mojo_shell_context_.reset(new MojoShellContext);
 #if defined(OS_MACOSX)
   mojo::edk::SetMachPortProvider(MachBroker::GetInstance());
 #endif  // defined(OS_MACOSX)
diff --git a/content/browser/compositor/image_transport_factory.h b/content/browser/compositor/image_transport_factory.h
index 8a398bd..c334c80 100644
--- a/content/browser/compositor/image_transport_factory.h
+++ b/content/browser/compositor/image_transport_factory.h
@@ -12,8 +12,8 @@
 #include "build/build_config.h"
 #include "cc/surfaces/surface_id_allocator.h"
 #include "content/common/content_export.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace cc {
 class SurfaceManager;
diff --git a/content/browser/compositor/software_browser_compositor_output_surface.cc b/content/browser/compositor/software_browser_compositor_output_surface.cc
index 4413c4c3..1ceacaae 100644
--- a/content/browser/compositor/software_browser_compositor_output_surface.cc
+++ b/content/browser/compositor/software_browser_compositor_output_surface.cc
@@ -16,8 +16,8 @@
 #include "cc/output/output_surface_client.h"
 #include "cc/output/software_output_device.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/vsync_provider.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.cc b/content/browser/dom_storage/dom_storage_context_wrapper.cc
index bde121a..49ab4e0 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.cc
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.cc
@@ -18,6 +18,7 @@
 #include "base/thread_task_runner_handle.h"
 #include "components/filesystem/public/interfaces/directory.mojom.h"
 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
+#include "components/profile_service/public/cpp/constants.h"
 #include "components/profile_service/public/interfaces/profile.mojom.h"
 #include "content/browser/dom_storage/dom_storage_area.h"
 #include "content/browser/dom_storage/dom_storage_context_impl.h"
@@ -26,9 +27,10 @@
 #include "content/browser/leveldb_wrapper_impl.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/local_storage_usage_info.h"
-#include "content/public/browser/mojo_app_connection.h"
 #include "content/public/browser/session_storage_usage_info.h"
 #include "mojo/common/common_type_converters.h"
+#include "services/shell/public/cpp/connection.h"
+#include "services/shell/public/cpp/connector.h"
 
 namespace content {
 namespace {
@@ -78,8 +80,8 @@
 // for now).
 class DOMStorageContextWrapper::MojoState {
  public:
-  MojoState(const std::string& mojo_user_id, const base::FilePath& subdirectory)
-      : mojo_user_id_(mojo_user_id),
+  MojoState(mojo::Connector* connector, const base::FilePath& subdirectory)
+      : connector_(connector),
         subdirectory_(subdirectory),
         connection_state_(NO_CONNECTION),
         weak_ptr_factory_(this) {}
@@ -107,8 +109,8 @@
   // Maps between an origin and its prefixed LevelDB view.
   std::map<url::Origin, std::unique_ptr<LevelDBWrapperImpl>> level_db_wrappers_;
 
-  std::string mojo_user_id_;
-  base::FilePath subdirectory_;
+  mojo::Connector* const connector_;
+  const base::FilePath subdirectory_;
 
   enum ConnectionState {
     NO_CONNECTION,
@@ -116,7 +118,8 @@
     CONNECTION_FINISHED
   } connection_state_;
 
-  std::unique_ptr<MojoAppConnection> profile_app_connection_;
+  std::unique_ptr<mojo::Connection> profile_app_connection_;
+
   profile::ProfileServicePtr profile_service_;
   filesystem::DirectoryPtr directory_;
 
@@ -134,9 +137,9 @@
     mojom::LevelDBWrapperRequest request) {
   // If we don't have a filesystem_connection_, we'll need to establish one.
   if (connection_state_ == NO_CONNECTION) {
-    profile_app_connection_ = MojoAppConnection::Create(
-        mojo_user_id_, "mojo:profile", kBrowserMojoAppUrl);
-
+    CHECK(connector_);
+    profile_app_connection_ =
+        connector_->Connect(profile::kProfileMojoApplicationName);
     connection_state_ = CONNECTION_IN_PROGRESS;
 
     if (!subdirectory_.empty()) {
@@ -229,14 +232,14 @@
 }
 
 DOMStorageContextWrapper::DOMStorageContextWrapper(
-    const std::string& mojo_user_id,
+    mojo::Connector* connector,
     const base::FilePath& profile_path,
     const base::FilePath& local_partition_path,
     storage::SpecialStoragePolicy* special_storage_policy) {
   base::FilePath storage_dir;
   if (!profile_path.empty())
     storage_dir = local_partition_path.AppendASCII(kLocalStorageDirectory);
-  mojo_state_.reset(new MojoState(mojo_user_id, storage_dir));
+  mojo_state_.reset(new MojoState(connector, storage_dir));
 
   base::FilePath data_path;
   if (!profile_path.empty())
diff --git a/content/browser/dom_storage/dom_storage_context_wrapper.h b/content/browser/dom_storage/dom_storage_context_wrapper.h
index 30bd48d..b631101 100644
--- a/content/browser/dom_storage/dom_storage_context_wrapper.h
+++ b/content/browser/dom_storage/dom_storage_context_wrapper.h
@@ -19,6 +19,10 @@
 class FilePath;
 }
 
+namespace mojo {
+class Connector;
+}
+
 namespace storage {
 class SpecialStoragePolicy;
 }
@@ -36,7 +40,7 @@
  public:
   // If |data_path| is empty, nothing will be saved to disk.
   DOMStorageContextWrapper(
-      const std::string& mojo_user_id,
+      mojo::Connector* connector,
       const base::FilePath& data_path,
       const base::FilePath& local_partition_path,
       storage::SpecialStoragePolicy* special_storage_policy);
diff --git a/content/browser/find_request_manager.cc b/content/browser/find_request_manager.cc
new file mode 100644
index 0000000..ad6b24e
--- /dev/null
+++ b/content/browser/find_request_manager.cc
@@ -0,0 +1,139 @@
+// 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 "content/browser/find_request_manager.h"
+
+#include "content/browser/frame_host/render_frame_host_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
+#include "content/common/frame_messages.h"
+#include "content/common/input_messages.h"
+
+namespace content {
+
+// static
+const int FindRequestManager::kInvalidId = -1;
+
+FindRequestManager::FindRequestManager(WebContentsImpl* web_contents)
+    : contents_(web_contents),
+      current_session_id_(kInvalidId),
+      number_of_matches_(0),
+      active_match_ordinal_(0) {}
+
+FindRequestManager::~FindRequestManager() {}
+
+void FindRequestManager::Find(int request_id,
+                              const base::string16& search_text,
+                              const blink::WebFindOptions& options) {
+  // Every find request must have a unique ID, and these IDs must strictly
+  // increase so that newer requests always have greater IDs than older
+  // requests.
+  DCHECK_GT(request_id, current_request_.id);
+  DCHECK_GT(request_id, current_session_id_);
+
+  FindRequest request(request_id, search_text, options);
+
+  if (options.findNext) {
+    // This is a find next operation.
+
+    // This implies that there is an ongoing find session with the same search
+    // text.
+    DCHECK_GE(current_session_id_, 0);
+    DCHECK_EQ(request.search_text, current_request_.search_text);
+  } else {
+    // This is an initial find operation.
+    Reset(request);
+  }
+
+  SendFindIPC(request, contents_->GetMainFrame());
+}
+
+void FindRequestManager::StopFinding(StopFindAction action) {
+  SendStopFindingIPC(action, contents_->GetMainFrame());
+  current_session_id_ = kInvalidId;
+}
+
+void FindRequestManager::OnFindReply(RenderFrameHost* rfh,
+                                     int request_id,
+                                     int number_of_matches,
+                                     const gfx::Rect& selection_rect,
+                                     int active_match_ordinal,
+                                     bool final_update) {
+  // Ignore stale replies from abandoned find sessions.
+  if (current_session_id_ == kInvalidId || request_id < current_session_id_)
+    return;
+
+  // Update the stored results.
+  number_of_matches_ = number_of_matches;
+  selection_rect_ = selection_rect;
+  active_match_ordinal_ = active_match_ordinal;
+
+  NotifyFindReply(request_id, final_update);
+}
+
+#if defined(OS_ANDROID)
+void FindRequestManager::ActivateNearestFindResult(float x,
+                                                   float y) {
+  if (current_session_id_ == kInvalidId)
+    return;
+
+  auto rfh = contents_->GetMainFrame();
+  rfh->Send(new InputMsg_ActivateNearestFindResult(
+      rfh->GetRoutingID(), current_session_id_, x, y));
+}
+
+void FindRequestManager::RequestFindMatchRects(int current_version) {
+  match_rects_.request_version = current_version;
+  SendFindMatchRectsIPC(contents_->GetMainFrame());
+}
+
+void FindRequestManager::OnFindMatchRectsReply(
+    RenderFrameHost* rfh,
+    int version,
+    const std::vector<gfx::RectF>& rects,
+    const gfx::RectF& active_rect) {
+  contents_->NotifyFindMatchRectsReply(version, rects, active_rect);
+}
+#endif
+
+void FindRequestManager::Reset(const FindRequest& initial_request) {
+  current_session_id_ = initial_request.id;
+  current_request_ = initial_request;
+  number_of_matches_ = 0;
+  active_match_ordinal_ = 0;
+  selection_rect_ = gfx::Rect();
+#if defined(OS_ANDROID)
+  match_rects_ = FindMatchRectsState();
+#endif
+}
+
+void FindRequestManager::SendFindIPC(const FindRequest& request,
+                                     RenderFrameHost* rfh) {
+  rfh->Send(new FrameMsg_Find(rfh->GetRoutingID(), request.id,
+                              request.search_text, request.options));
+}
+
+void FindRequestManager::SendStopFindingIPC(StopFindAction action,
+                                            RenderFrameHost* rfh) const {
+  rfh->Send(new FrameMsg_StopFinding(rfh->GetRoutingID(), action));
+}
+
+void FindRequestManager::NotifyFindReply(int request_id,
+                                         bool final_update) const {
+  if (request_id == kInvalidId) {
+    NOTREACHED();
+    return;
+  }
+
+  contents_->NotifyFindReply(request_id, number_of_matches_, selection_rect_,
+                             active_match_ordinal_, final_update);
+}
+
+#if defined(OS_ANDROID)
+void FindRequestManager::SendFindMatchRectsIPC(RenderFrameHost* rfh) {
+  rfh->Send(new FrameMsg_FindMatchRects(rfh->GetRoutingID(),
+                                        match_rects_.request_version));
+}
+#endif
+
+}  // namespace content
diff --git a/content/browser/find_request_manager.h b/content/browser/find_request_manager.h
new file mode 100644
index 0000000..0fa037e
--- /dev/null
+++ b/content/browser/find_request_manager.h
@@ -0,0 +1,142 @@
+// 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 CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
+#define CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
+
+#include <set>
+#include <vector>
+
+#include "content/public/common/stop_find_action.h"
+#include "third_party/WebKit/public/web/WebFindOptions.h"
+#include "ui/gfx/geometry/rect.h"
+#include "ui/gfx/geometry/rect_f.h"
+
+namespace content {
+
+class RenderFrameHost;
+class WebContentsImpl;
+
+// FindRequestManager manages all of the find-in-page requests/replies
+// initiated/received through a WebContents. It coordinates searching across
+// multiple (potentially out-of-process) frames, handles the aggregation of find
+// results from each frame, and facilitates active match traversal. It is
+// instantiated once per WebContents, and is owned by that WebContents.
+//
+// TODO(paulmeyer): FindRequestManager is currently incomplete and does not do
+// all of these things yet, but will soon.
+class FindRequestManager {
+ public:
+  explicit FindRequestManager(WebContentsImpl* web_contents);
+  ~FindRequestManager();
+
+  // Initiates a find operation for |search_text| with the options specified in
+  // |options|. |request_id| uniquely identifies the find request.
+  void Find(int request_id,
+            const base::string16& search_text,
+            const blink::WebFindOptions& options);
+
+  // Stops the active find session and clears the general highlighting of the
+  // matches. |action| determines whether the last active match (if any) will be
+  // activated, cleared, or remain highlighted.
+  void StopFinding(StopFindAction action);
+
+  // Called when a reply is received from a frame with the results from a
+  // find request.
+  void OnFindReply(RenderFrameHost* rfh,
+                   int request_id,
+                   int number_of_matches,
+                   const gfx::Rect& selection_rect,
+                   int active_match_ordinal,
+                   bool final_update);
+
+#if defined(OS_ANDROID)
+  // Selects and zooms to the find result nearest to the point (x,y) defined in
+  // find-in-page coordinates.
+  void ActivateNearestFindResult(float x, float y);
+
+  // Requests the rects of the current find matches from the renderer process.
+  void RequestFindMatchRects(int current_version);
+
+  // Called when a reply is received in response to a request for find match
+  // rects.
+  void OnFindMatchRectsReply(RenderFrameHost* rfh,
+                             int version,
+                             const std::vector<gfx::RectF>& rects,
+                             const gfx::RectF& active_rect);
+#endif
+
+ private:
+  // An invalid ID. This value is invalid for any render process ID, render
+  // frame ID, or find request ID.
+  static const int kInvalidId;
+
+  // The request data for a single find request.
+  struct FindRequest {
+    // The find request ID that uniquely identifies this find request.
+    int id = kInvalidId;
+
+    // The text that is being searched for in this find request.
+    base::string16 search_text;
+
+    // The set of find options in effect for this find request.
+    blink::WebFindOptions options;
+
+    FindRequest() = default;
+    FindRequest(int id,
+                const base::string16& search_text,
+                const blink::WebFindOptions& options)
+        : id(id), search_text(search_text), options(options) {}
+  };
+
+  // Send a find IPC containing the find request |request| to the RenderFrame
+  // associated with |rfh|.
+  void SendFindIPC(const FindRequest& request, RenderFrameHost* rfh);
+
+  // Send a stop finding IPC to the RenderFrame associated with |rfh|.
+  void SendStopFindingIPC(StopFindAction action, RenderFrameHost* rfh) const;
+
+  // Reset all of the per-session state for a new find-in-page session.
+  void Reset(const FindRequest& initial_request);
+
+  // Send the find results (as they currently are) to the WebContents.
+  void NotifyFindReply(int request_id, bool final_update) const;
+
+#if defined(OS_ANDROID)
+  // Request the latest find match rects from a frame.
+  void SendFindMatchRectsIPC(RenderFrameHost* rfh);
+
+  // State related to FindMatchRects requests.
+  struct FindMatchRectsState {
+    // The latest find match rects version known by the requester.
+    int request_version = kInvalidId;
+  } match_rects_;
+#endif
+
+  // The WebContents that owns this FindRequestManager.
+  WebContentsImpl* const contents_;
+
+  // The request ID of the initial find request in the current find-in-page
+  // session, which uniquely identifies this session. Request IDs are included
+  // in all find-related IPCs, which allows reply IPCs containing results from
+  // previous sessions (with |request_id| < |current_session_id_|) to be easily
+  // identified and ignored.
+  int current_session_id_;
+
+  // The current find request.
+  FindRequest current_request_;
+
+  // The total number of matches found in the current find-in-page session.
+  int number_of_matches_;
+
+  // The overall active match ordinal for the current find-in-page session.
+  int active_match_ordinal_;
+
+  // The rectangle around the active match, in screen coordinates.
+  gfx::Rect selection_rect_;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_FIND_REQUEST_MANAGER_H_
diff --git a/content/browser/frame_host/cross_process_frame_connector.cc b/content/browser/frame_host/cross_process_frame_connector.cc
index b5e415c..1d22345 100644
--- a/content/browser/frame_host/cross_process_frame_connector.cc
+++ b/content/browser/frame_host/cross_process_frame_connector.cc
@@ -102,13 +102,9 @@
   surface->AddDestructionDependency(sequence);
 }
 
-void CrossProcessFrameConnector::OnInitializeChildFrame(gfx::Rect frame_rect,
-                                                        float scale_factor) {
+void CrossProcessFrameConnector::OnInitializeChildFrame(float scale_factor) {
   if (scale_factor != device_scale_factor_)
     SetDeviceScaleFactor(scale_factor);
-
-  if (!frame_rect.size().IsEmpty())
-    SetRect(frame_rect);
 }
 
 gfx::Rect CrossProcessFrameConnector::ChildFrameRect() {
diff --git a/content/browser/frame_host/cross_process_frame_connector.h b/content/browser/frame_host/cross_process_frame_connector.h
index 0eebdbb..a6b3b0d 100644
--- a/content/browser/frame_host/cross_process_frame_connector.h
+++ b/content/browser/frame_host/cross_process_frame_connector.h
@@ -123,7 +123,7 @@
   void OnForwardInputEvent(const blink::WebInputEvent* event);
   void OnFrameRectChanged(const gfx::Rect& frame_rect);
   void OnVisibilityChanged(bool visible);
-  void OnInitializeChildFrame(gfx::Rect frame_rect, float scale_factor);
+  void OnInitializeChildFrame(float scale_factor);
   void OnSatisfySequence(const cc::SurfaceSequence& sequence);
   void OnRequireSequence(const cc::SurfaceId& id,
                          const cc::SurfaceSequence& sequence);
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 72f79181..b83ef55f 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2518,17 +2518,6 @@
 
 #elif defined(OS_ANDROID)
 
-void RenderFrameHostImpl::ActivateNearestFindResult(int request_id,
-                                                    float x,
-                                                    float y) {
-  Send(
-      new InputMsg_ActivateNearestFindResult(GetRoutingID(), request_id, x, y));
-}
-
-void RenderFrameHostImpl::RequestFindMatchRects(int current_version) {
-  Send(new FrameMsg_FindMatchRects(GetRoutingID(), current_version));
-}
-
 void RenderFrameHostImpl::DidSelectPopupMenuItems(
     const std::vector<int>& selected_indices) {
   Send(new FrameMsg_SelectPopupMenuItems(routing_id_, false, selected_indices));
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 3292e3a95..b3b0378 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -149,10 +149,6 @@
   blink::WebPageVisibilityState GetVisibilityState() override;
   bool IsRenderFrameLive() override;
   int GetProxyCount() override;
-#if defined(OS_ANDROID)
-  void ActivateNearestFindResult(int request_id, float x, float y) override;
-  void RequestFindMatchRects(int current_version) override;
-#endif
 
   // IPC::Sender
   bool Send(IPC::Message* msg) override;
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 2e30fec..fcf2ff3 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -53,8 +53,8 @@
 #include "ipc/message_filter.h"
 #include "media/base/media_switches.h"
 #include "ui/base/ui_base_switches.h"
-#include "ui/events/latency_info.h"
 #include "ui/gl/gl_switches.h"
+#include "ui/latency_info/latency_info.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
diff --git a/content/browser/loader/resource_scheduler_unittest.cc b/content/browser/loader/resource_scheduler_unittest.cc
index 59b6d00..98003ce7 100644
--- a/content/browser/loader/resource_scheduler_unittest.cc
+++ b/content/browser/loader/resource_scheduler_unittest.cc
@@ -30,7 +30,7 @@
 #include "net/url_request/url_request.h"
 #include "net/url_request/url_request_test_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using std::string;
 
diff --git a/content/browser/media/session/media_session_delegate_android_browsertest.cc b/content/browser/media/session/media_session_delegate_android_browsertest.cc
index e32997a..263d5832 100644
--- a/content/browser/media/session/media_session_delegate_android_browsertest.cc
+++ b/content/browser/media/session/media_session_delegate_android_browsertest.cc
@@ -17,7 +17,9 @@
 // is the only way found to actually reproduce the crash so as a result, the
 // test will only run on builds without DCHECK's.
 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
-#define MAYBE_OnAudioFocusChangeAfterDtorCrash OnAudioFocusChangeAfterDtorCrash
+// TODO(crbug.com/602787) The test is flaky, disabling it everywhere.
+#define MAYBE_OnAudioFocusChangeAfterDtorCrash \
+  DISABLED_OnAudioFocusChangeAfterDtorCrash
 #else
 #define MAYBE_OnAudioFocusChangeAfterDtorCrash \
   DISABLED_OnAudioFocusChangeAfterDtorCrash
diff --git a/content/browser/mojo/browser_shell_connection.cc b/content/browser/mojo/browser_shell_connection.cc
new file mode 100644
index 0000000..8fb9121
--- /dev/null
+++ b/content/browser/mojo/browser_shell_connection.cc
@@ -0,0 +1,65 @@
+// 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 "content/browser/mojo/browser_shell_connection.h"
+
+#include "content/browser/mojo/constants.h"
+#include "services/shell/public/interfaces/connector.mojom.h"
+
+namespace content {
+
+BrowserShellConnection::BrowserShellConnection(
+    mojo::shell::mojom::ShellClientRequest request)
+    : shell_connection_(new mojo::ShellConnection(this, std::move(request))) {}
+
+BrowserShellConnection::~BrowserShellConnection() {}
+
+mojo::Connector* BrowserShellConnection::GetConnector() {
+  return shell_connection_->connector();
+}
+
+void BrowserShellConnection::AddEmbeddedApplication(
+    const base::StringPiece& name,
+    const EmbeddedApplicationRunner::FactoryCallback& callback,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) {
+  std::unique_ptr<EmbeddedApplicationRunner> app(
+      new EmbeddedApplicationRunner(callback, task_runner));
+  auto result = embedded_apps_.insert(
+      std::make_pair(name.as_string(), std::move(app)));
+  DCHECK(result.second);
+}
+
+bool BrowserShellConnection::AcceptConnection(mojo::Connection* connection) {
+  std::string remote_app = connection->GetRemoteIdentity().name();
+  if (remote_app == "mojo:shell") {
+    // Only expose the SCF interface to the shell.
+    connection->AddInterface<mojo::shell::mojom::ShellClientFactory>(this);
+    return true;
+  }
+
+  // Allow connections from the root browser application.
+  if (remote_app == kBrowserMojoApplicationName &&
+      connection->GetRemoteIdentity().user_id() ==
+          mojo::shell::mojom::kRootUserID)
+    return true;
+
+  // Reject all other connections to this application.
+  return false;
+}
+
+void BrowserShellConnection::Create(
+    mojo::Connection* connection,
+    mojo::shell::mojom::ShellClientFactoryRequest request) {
+  factory_bindings_.AddBinding(this, std::move(request));
+}
+
+void BrowserShellConnection::CreateShellClient(
+    mojo::shell::mojom::ShellClientRequest request,
+    const mojo::String& name) {
+  auto it = embedded_apps_.find(name);
+  if (it != embedded_apps_.end())
+    it->second->BindShellClientRequest(std::move(request));
+}
+
+}  // namespace content
diff --git a/content/browser/mojo/browser_shell_connection.h b/content/browser/mojo/browser_shell_connection.h
new file mode 100644
index 0000000..6a38234
--- /dev/null
+++ b/content/browser/mojo/browser_shell_connection.h
@@ -0,0 +1,74 @@
+// 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 CONTENT_BROWSER_MOJO_BROWSER_SHELL_CONNECTION_H_
+#define CONTENT_BROWSER_MOJO_BROWSER_SHELL_CONNECTION_H_
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "base/strings/string_piece.h"
+#include "content/common/mojo/embedded_application_runner.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
+#include "services/shell/public/cpp/connector.h"
+#include "services/shell/public/cpp/interface_factory.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/cpp/shell_connection.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+#include "services/shell/public/interfaces/shell_client_factory.mojom.h"
+
+namespace content {
+
+// A connection from the browser process to the Mojo shell. There may be
+// multiple connections in a single browser process. Each connection may have
+// its own identity, e.g., a connection with unique user ID per BrowserContext.
+class BrowserShellConnection
+    : public mojo::ShellClient,
+      public mojo::InterfaceFactory<mojo::shell::mojom::ShellClientFactory>,
+      public mojo::shell::mojom::ShellClientFactory {
+ public:
+  explicit BrowserShellConnection(
+      mojo::shell::mojom::ShellClientRequest request);
+  ~BrowserShellConnection() override;
+
+  mojo::Connector* GetConnector();
+
+  // Adds an embedded application to this connection's ShellClientFactory.
+  // |callback| will be used to create a new instance of the application on
+  // |task_runner|'s thread if no instance is running when an incoming
+  // connection is made to |name|. If |task_runner| is null, the calling thread
+  // will be used to run the application.
+  void AddEmbeddedApplication(
+      const base::StringPiece& name,
+      const EmbeddedApplicationRunner::FactoryCallback& callback,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+ private:
+  // mojo::ShellClient:
+  bool AcceptConnection(mojo::Connection* connection) override;
+
+  // mojo::InterfaceFactory<mojo::shell::mojom::ShellClientFactory>:
+  void Create(mojo::Connection* connection,
+              mojo::shell::mojom::ShellClientFactoryRequest request) override;
+
+  // mojo::shell::mojom::ShellClientFactory:
+  void CreateShellClient(mojo::shell::mojom::ShellClientRequest request,
+                         const mojo::String& name) override;
+
+  std::unique_ptr<mojo::ShellConnection> shell_connection_;
+  mojo::BindingSet<mojo::shell::mojom::ShellClientFactory> factory_bindings_;
+  std::unordered_map<std::string, std::unique_ptr<EmbeddedApplicationRunner>>
+      embedded_apps_;
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserShellConnection);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_MOJO_BROWSER_SHELL_CONNECTION_H_
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 0d134152..1a263ab 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -4,6 +4,7 @@
 
 #include "content/browser/mojo/mojo_shell_context.h"
 
+#include <unordered_map>
 #include <utility>
 
 #include "base/bind.h"
@@ -14,11 +15,10 @@
 #include "base/path_service.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "components/profile_service/profile_app.h"
+#include "components/profile_service/public/cpp/constants.h"
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/browser/mojo/constants.h"
 #include "content/common/gpu_process_launch_causes.h"
-#include "content/common/mojo/current_thread_loader.h"
 #include "content/common/mojo/mojo_shell_connection_impl.h"
 #include "content/common/mojo/static_loader.h"
 #include "content/common/process_control.mojom.h"
@@ -70,21 +70,6 @@
     LOG(ERROR) << "Failed to launch Mojo application for " << name;
 }
 
-// The default loader to use for all applications. This does nothing but drop
-// the Application request.
-class DefaultLoader : public mojo::shell::Loader {
- public:
-   DefaultLoader() {}
-   ~DefaultLoader() override {}
-
- private:
-  // mojo::shell::Loader:
-  void Load(const std::string& name,
-            mojo::shell::mojom::ShellClientRequest request) override {}
-
-  DISALLOW_COPY_AND_ASSIGN(DefaultLoader);
-};
-
 // This launches a utility process and forwards the Load request the
 // mojom::ProcessControl service there. The utility process is sandboxed iff
 // |use_sandbox| is true.
@@ -157,11 +142,6 @@
   DISALLOW_COPY_AND_ASSIGN(GpuProcessLoader);
 };
 
-std::string GetStringResource(int id) {
-  return GetContentClient()->GetDataResource(
-      id, ui::ScaleFactor::SCALE_FACTOR_NONE).as_string();
-}
-
 }  // namespace
 
 // A ManifestProvider which resolves application names to builtin manifest
@@ -172,25 +152,26 @@
   BuiltinManifestProvider() {}
   ~BuiltinManifestProvider() override {}
 
+  void AddManifestResource(const std::string& name, int resource_id) {
+    auto result = manifest_resources_.insert(
+        std::make_pair(name, resource_id));
+    DCHECK(result.second);
+  }
+
  private:
   // catalog::ManifestProvider:
   bool GetApplicationManifest(const base::StringPiece& name,
                               std::string* manifest_contents) override {
-    if (name == "mojo:catalog") {
-      *manifest_contents = GetStringResource(IDR_MOJO_CATALOG_MANIFEST);
-      return true;
-    } else if (name == kBrowserMojoApplicationName) {
-      *manifest_contents = GetStringResource(IDR_MOJO_CONTENT_BROWSER_MANIFEST);
-      return true;
-    } else if (name == kRendererMojoApplicationName) {
-      *manifest_contents =
-          GetStringResource(IDR_MOJO_CONTENT_RENDERER_MANIFEST);
-      return true;
-    }
-
-    return false;
+    auto it = manifest_resources_.find(name.as_string());
+    if (it == manifest_resources_.end())
+      return false;
+    *manifest_contents = GetContentClient()->GetDataResource(
+        it->second, ui::ScaleFactor::SCALE_FACTOR_NONE).as_string();
+    return true;
   }
 
+  std::unordered_map<std::string, int> manifest_resources_;
+
   DISALLOW_COPY_AND_ASSIGN(BuiltinManifestProvider);
 };
 
@@ -244,9 +225,7 @@
   g_applications_for_test = apps;
 }
 
-MojoShellContext::MojoShellContext(
-    scoped_refptr<base::SingleThreadTaskRunner> file_thread,
-    scoped_refptr<base::SingleThreadTaskRunner> db_thread) {
+MojoShellContext::MojoShellContext() {
   proxy_.Get().reset(new Proxy(this));
 
   scoped_refptr<base::SingleThreadTaskRunner> file_task_runner =
@@ -254,13 +233,21 @@
   std::unique_ptr<mojo::shell::NativeRunnerFactory> native_runner_factory(
       new mojo::shell::InProcessNativeRunnerFactory(
           BrowserThread::GetBlockingPool()));
+
   manifest_provider_.reset(new BuiltinManifestProvider);
+  manifest_provider_->AddManifestResource(kBrowserMojoApplicationName,
+                                          IDR_MOJO_CONTENT_BROWSER_MANIFEST);
+  manifest_provider_->AddManifestResource(kRendererMojoApplicationName,
+                                          IDR_MOJO_CONTENT_RENDERER_MANIFEST);
+  manifest_provider_->AddManifestResource("mojo:catalog",
+                                          IDR_MOJO_CATALOG_MANIFEST);
+  manifest_provider_->AddManifestResource(profile::kProfileMojoApplicationName,
+                                          IDR_MOJO_PROFILE_MANIFEST);
+
   catalog_.reset(new catalog::Factory(file_task_runner.get(), nullptr,
                                       manifest_provider_.get()));
   shell_.reset(new mojo::shell::Shell(std::move(native_runner_factory),
                                       catalog_->TakeShellClient()));
-  shell_->set_default_loader(
-      std::unique_ptr<mojo::shell::Loader>(new DefaultLoader));
 
   StaticApplicationMap apps;
   GetContentClient()->browser()->RegisterInProcessMojoApplications(&apps);
@@ -300,15 +287,6 @@
                            "mojo:media");
 #endif
 
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kMojoLocalStorage)) {
-    base::Callback<std::unique_ptr<mojo::ShellClient>()> profile_callback =
-        base::Bind(&profile::CreateProfileApp, file_thread, db_thread);
-    shell_->SetLoaderForName(
-        base::WrapUnique(new CurrentThreadLoader(profile_callback)),
-        "mojo:profile");
-  }
-
   if (!IsRunningInMojoShell()) {
     MojoShellConnection::Create(
         shell_->InitInstanceForEmbedder(kBrowserMojoApplicationName),
diff --git a/content/browser/mojo/mojo_shell_context.h b/content/browser/mojo/mojo_shell_context.h
index 738c3819..08a9500f1 100644
--- a/content/browser/mojo/mojo_shell_context.h
+++ b/content/browser/mojo/mojo_shell_context.h
@@ -12,7 +12,6 @@
 #include "base/compiler_specific.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
-#include "base/single_thread_task_runner.h"
 #include "content/common/content_export.h"
 #include "services/shell/public/interfaces/connector.mojom.h"
 #include "services/shell/shell.h"
@@ -35,8 +34,7 @@
       std::map<std::string,
                base::Callback<std::unique_ptr<mojo::ShellClient>()>>;
 
-  MojoShellContext(scoped_refptr<base::SingleThreadTaskRunner> file_thread,
-                   scoped_refptr<base::SingleThreadTaskRunner> db_thread);
+  MojoShellContext();
   ~MojoShellContext();
 
   // Connects an application at |name| and gets a handle to its exposed
diff --git a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
index 7711e2d..1c3bd74 100644
--- a/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
+++ b/content/browser/renderer_host/input/non_blocking_event_browsertest.cc
@@ -27,7 +27,7 @@
 #include "content/shell/browser/shell.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/event_switches.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebInputEvent;
 
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 633e4e87..2afffe8 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
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "content/browser/renderer_host/event_with_latency_info.h"
 #include "content/common/content_export.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
index e1fd3b0..74abdc6 100644
--- a/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
+++ b/content/browser/renderer_host/input/synthetic_gesture_target_base.cc
@@ -10,7 +10,7 @@
 #include "content/common/input_messages.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/event.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebInputEvent;
 using blink::WebTouchEvent;
diff --git a/content/browser/renderer_host/input/synthetic_pointer_action.cc b/content/browser/renderer_host/input/synthetic_pointer_action.cc
index 6353f34..cb144b1 100644
--- a/content/browser/renderer_host/input/synthetic_pointer_action.cc
+++ b/content/browser/renderer_host/input/synthetic_pointer_action.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/synthetic_tap_gesture.cc b/content/browser/renderer_host/input/synthetic_tap_gesture.cc
index 46dc23ae..1242d826 100644
--- a/content/browser/renderer_host/input/synthetic_tap_gesture.cc
+++ b/content/browser/renderer_host/input/synthetic_tap_gesture.cc
@@ -6,7 +6,7 @@
 
 #include "base/logging.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc b/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc
index 3a317822b..6fff6819 100644
--- a/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc
+++ b/content/browser/renderer_host/input/synthetic_touchscreen_pinch_gesture.cc
@@ -9,7 +9,7 @@
 #include <cmath>
 
 #include "base/logging.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/input/touch_action_browsertest.cc b/content/browser/renderer_host/input/touch_action_browsertest.cc
index 2c4ab95..17516af 100644
--- a/content/browser/renderer_host/input/touch_action_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_action_browsertest.cc
@@ -32,7 +32,7 @@
 #include "content/shell/browser/shell.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/event_switches.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebInputEvent;
 
diff --git a/content/browser/renderer_host/input/touch_input_browsertest.cc b/content/browser/renderer_host/input/touch_input_browsertest.cc
index 7ff1dd0..d374b2c 100644
--- a/content/browser/renderer_host/input/touch_input_browsertest.cc
+++ b/content/browser/renderer_host/input/touch_input_browsertest.cc
@@ -25,7 +25,7 @@
 #include "content/shell/browser/shell.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/event_switches.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebInputEvent;
 
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index eea865b..bf8bd1a 100644
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -15,13 +15,13 @@
 #include "content/browser/renderer_host/pepper/pepper_file_system_browser_host.h"
 #include "content/browser/renderer_host/pepper/pepper_security_helper.h"
 #include "content/common/fileapi/file_system_messages.h"
-#include "content/common/sandbox_util.h"
 #include "content/common/view_messages.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/content_browser_client.h"
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/content_client.h"
+#include "ipc/ipc_platform_file.h"
 #include "ppapi/c/pp_errors.h"
 #include "ppapi/c/ppb_file_io.h"
 #include "ppapi/host/dispatch_host_message.h"
@@ -480,14 +480,8 @@
 bool PepperFileIOHost::AddFileToReplyContext(
     int32_t open_flags,
     ppapi::host::ReplyMessageContext* reply_context) const {
-  base::ProcessId plugin_process_id =
-      base::GetProcId(browser_ppapi_host_->GetPluginProcess().Handle());
-  if (plugin_process_id == base::kNullProcessId)
-    plugin_process_id = resolved_render_process_id_;
-
   IPC::PlatformFileForTransit transit_file =
-      BrokerGetFileHandleForProcess(file_.GetPlatformFile(), plugin_process_id,
-                                    false);
+      IPC::GetPlatformFileForTransit(file_.GetPlatformFile(), false);
   if (transit_file == IPC::InvalidPlatformFileForTransit())
     return false;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 43047c2..7dfd14d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.h
+++ b/content/browser/renderer_host/render_widget_host_impl.h
@@ -43,8 +43,8 @@
 #include "ui/base/ime/text_input_mode.h"
 #include "ui/base/ime/text_input_type.h"
 #include "ui/events/gesture_detection/gesture_provider_config_helper.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/latency_info/latency_info.h"
 
 struct FrameHostMsg_HittestData_Params;
 struct ViewHostMsg_SelectionBounds_Params;
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index e001238..8f350eb8 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -751,6 +751,130 @@
       DepictFrameTree(root));
 }
 
+// Class to sniff incoming IPCs for FrameHostMsg_FrameRectChanged messages.
+class FrameRectChangedMessageFilter : public content::BrowserMessageFilter {
+ public:
+  FrameRectChangedMessageFilter()
+      : content::BrowserMessageFilter(FrameMsgStart),
+        message_loop_runner_(new content::MessageLoopRunner),
+        frame_rect_received_(false) {}
+
+  bool OnMessageReceived(const IPC::Message& message) override {
+    IPC_BEGIN_MESSAGE_MAP(FrameRectChangedMessageFilter, message)
+      IPC_MESSAGE_HANDLER(FrameHostMsg_FrameRectChanged, OnFrameRectChanged)
+    IPC_END_MESSAGE_MAP()
+    return false;
+  }
+
+  gfx::Rect last_rect() const { return last_rect_; }
+
+  void Wait() {
+    last_rect_ = gfx::Rect();
+    message_loop_runner_->Run();
+  }
+
+ private:
+  ~FrameRectChangedMessageFilter() override {}
+
+  void OnFrameRectChanged(const gfx::Rect& rect) {
+    content::BrowserThread::PostTask(
+        content::BrowserThread::UI, FROM_HERE,
+        base::Bind(&FrameRectChangedMessageFilter::OnFrameRectChangedOnUI, this,
+                   rect));
+  }
+
+  void OnFrameRectChangedOnUI(const gfx::Rect& rect) {
+    last_rect_ = rect;
+    if (!frame_rect_received_) {
+      frame_rect_received_ = true;
+      message_loop_runner_->Quit();
+    }
+  }
+
+  scoped_refptr<content::MessageLoopRunner> message_loop_runner_;
+  bool frame_rect_received_;
+  gfx::Rect last_rect_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameRectChangedMessageFilter);
+};
+
+// Test that the view bounds for an out-of-process iframe are set and updated
+// correctly, including accounting for local frame offsets in the parent and
+// scroll positions.
+#if defined(OS_ANDROID)
+// Browser process hit testing is not implemented on Android.
+// https://crbug.com/491334
+#define MAYBE_ViewBoundsInNestedFrameTest DISABLED_ViewBoundsInNestedFrameTest
+#else
+#define MAYBE_ViewBoundsInNestedFrameTest ViewBoundsInNestedFrameTest
+#endif
+IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
+                       MAYBE_ViewBoundsInNestedFrameTest) {
+  GURL main_url(embedded_test_server()->GetURL(
+      "a.com", "/cross_site_iframe_factory.html?a(a)"));
+  NavigateToURL(shell(), main_url);
+
+  // It is safe to obtain the root frame tree node here, as it doesn't change.
+  FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
+                            ->GetFrameTree()
+                            ->root();
+  RenderWidgetHostViewBase* rwhv_root = static_cast<RenderWidgetHostViewBase*>(
+      root->current_frame_host()->GetRenderWidgetHost()->GetView());
+  ASSERT_EQ(1U, root->child_count());
+
+  FrameTreeNode* parent_iframe_node = root->child_at(0);
+  GURL site_url(embedded_test_server()->GetURL(
+      "a.com", "/frame_tree/page_with_positioned_frame.html"));
+  NavigateFrameToURL(parent_iframe_node, site_url);
+
+  EXPECT_EQ(
+      " Site A ------------ proxies for B\n"
+      "   +--Site A ------- proxies for B\n"
+      "        +--Site B -- proxies for A\n"
+      "Where A = http://a.com/\n"
+      "      B = http://baz.com/",
+      DepictFrameTree(root));
+
+  FrameTreeNode* nested_iframe_node = parent_iframe_node->child_at(0);
+  RenderWidgetHostViewBase* rwhv_nested =
+      static_cast<RenderWidgetHostViewBase*>(
+          nested_iframe_node->current_frame_host()
+              ->GetRenderWidgetHost()
+              ->GetView());
+
+  SurfaceHitTestReadyNotifier notifier(
+      static_cast<RenderWidgetHostViewChildFrame*>(rwhv_nested));
+  notifier.WaitForSurfaceReady();
+
+  // Verify the view bounds of the nested iframe, which should account for the
+  // relative offset of its direct parent within the root frame.
+  gfx::Rect bounds = rwhv_nested->GetViewBounds();
+  EXPECT_EQ(bounds.x() - rwhv_root->GetViewBounds().x(), 397);
+  EXPECT_EQ(bounds.y() - rwhv_root->GetViewBounds().y(), 112);
+
+  scoped_refptr<FrameRectChangedMessageFilter> filter =
+      new FrameRectChangedMessageFilter();
+  root->current_frame_host()->GetProcess()->AddFilter(filter.get());
+
+  // Scroll the parent frame downward to verify that the child rect gets updated
+  // correctly.
+  blink::WebMouseWheelEvent scroll_event;
+  scroll_event.type = blink::WebInputEvent::MouseWheel;
+  scroll_event.x = 387;
+  scroll_event.y = 110;
+  scroll_event.deltaX = 0.0f;
+  scroll_event.deltaY = -30.0f;
+  rwhv_root->ProcessMouseWheelEvent(scroll_event);
+
+  filter->Wait();
+
+  // The precise amount of scroll for the first view position update is not
+  // deterministic, so this simply verifies that the OOPIF moved from its
+  // earlier position.
+  gfx::Rect update_rect = filter->last_rect();
+  EXPECT_LT(update_rect.y(), bounds.y() - rwhv_root->GetViewBounds().y());
+}
+
 // Test that mouse events are being routed to the correct RenderWidgetHostView
 // based on coordinates.
 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
diff --git a/content/browser/storage_partition_impl.cc b/content/browser/storage_partition_impl.cc
index dd35f88..68529ea 100644
--- a/content/browser/storage_partition_impl.cc
+++ b/content/browser/storage_partition_impl.cc
@@ -465,7 +465,7 @@
 
   scoped_refptr<DOMStorageContextWrapper> dom_storage_context =
       new DOMStorageContextWrapper(
-          BrowserContext::GetMojoUserIdFor(context),
+          BrowserContext::GetMojoConnectorFor(context),
           in_memory ? base::FilePath() : context->GetPath(),
           relative_partition_path, context->GetSpecialStoragePolicy());
 
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 059d2989..efb92b12 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -40,6 +40,7 @@
 #include "content/browser/download/download_stats.h"
 #include "content/browser/download/mhtml_generation_manager.h"
 #include "content/browser/download/save_package.h"
+#include "content/browser/find_request_manager.h"
 #include "content/browser/frame_host/cross_process_frame_connector.h"
 #include "content/browser/frame_host/interstitial_page_impl.h"
 #include "content/browser/frame_host/navigation_entry_impl.h"
@@ -642,7 +643,6 @@
     IPC_MESSAGE_HANDLER(FrameHostMsg_EndColorChooser, OnEndColorChooser)
     IPC_MESSAGE_HANDLER(FrameHostMsg_SetSelectedColorInColorChooser,
                         OnSetSelectedColorInColorChooser)
-
     IPC_MESSAGE_HANDLER(ViewHostMsg_DidFirstVisuallyNonEmptyPaint,
                         OnFirstVisuallyNonEmptyPaint)
     IPC_MESSAGE_HANDLER(FrameHostMsg_DidLoadResourceFromMemoryCache,
@@ -2998,22 +2998,24 @@
   }
 
   // See if a top level browser plugin handles the find request first.
+  // TODO(paulmeyer): Remove this after find-in-page works across GuestViews.
   if (browser_plugin_embedder_ &&
       browser_plugin_embedder_->Find(request_id, search_text, options)) {
     return;
   }
-  GetMainFrame()->Send(new FrameMsg_Find(GetMainFrame()->GetRoutingID(),
-                                         request_id, search_text, options));
+
+  GetOrCreateFindRequestManager()->Find(request_id, search_text, options);
 }
 
 void WebContentsImpl::StopFinding(StopFindAction action) {
   // See if a top level browser plugin handles the stop finding request first.
+  // TODO(paulmeyer): Remove this after find-in-page works across GuestViews.
   if (browser_plugin_embedder_ &&
       browser_plugin_embedder_->StopFinding(action)) {
     return;
   }
-  GetMainFrame()->Send(
-      new FrameMsg_StopFinding(GetMainFrame()->GetRoutingID(), action));
+
+  GetOrCreateFindRequestManager()->StopFinding(action);
 }
 
 void WebContentsImpl::InsertCSS(const std::string& css) {
@@ -3531,10 +3533,14 @@
                                   const gfx::Rect& selection_rect,
                                   int active_match_ordinal,
                                   bool final_update) {
-  if (delegate_) {
-    delegate_->FindReply(this, request_id, number_of_matches, selection_rect,
-                         active_match_ordinal, final_update);
-  }
+  // Forward the find reply to the FindRequestManager, along with the
+  // RenderFrameHost associated with the frame that the reply came from.
+  GetOrCreateFindRequestManager()->OnFindReply(render_frame_message_source_,
+                                               request_id,
+                                               number_of_matches,
+                                               selection_rect,
+                                               active_match_ordinal,
+                                               final_update);
 }
 
 #if defined(OS_ANDROID)
@@ -3542,8 +3548,8 @@
     int version,
     const std::vector<gfx::RectF>& rects,
     const gfx::RectF& active_rect) {
-  if (delegate_)
-    delegate_->FindMatchRectsReply(this, version, rects, active_rect);
+  GetOrCreateFindRequestManager()->OnFindMatchRectsReply(
+      render_frame_message_source_, version, rects, active_rect);
 }
 
 void WebContentsImpl::OnOpenDateTimeDialog(
@@ -4745,6 +4751,15 @@
   return web_contents_android;
 }
 
+void WebContentsImpl::ActivateNearestFindResult(float x,
+                                                float y) {
+  GetOrCreateFindRequestManager()->ActivateNearestFindResult(x, y);
+}
+
+void WebContentsImpl::RequestFindMatchRects(int current_version) {
+  GetOrCreateFindRequestManager()->RequestFindMatchRects(current_version);
+}
+
 bool WebContentsImpl::CreateRenderViewForInitialEmptyDocument() {
   return CreateRenderViewForRenderManager(
       GetRenderViewHost(), MSG_ROUTING_NONE, MSG_ROUTING_NONE,
@@ -4901,6 +4916,37 @@
   return NULL;
 }
 
+FindRequestManager* WebContentsImpl::GetOrCreateFindRequestManager() {
+  // TODO(paulmeyer): This method will need to access (or potentially create)
+  // the FindRequestManager in the outermost WebContents once find-in-page
+  // across GuestViews is implemented.
+  if (!find_request_manager_)
+    find_request_manager_.reset(new FindRequestManager(this));
+
+  return find_request_manager_.get();
+}
+
+void WebContentsImpl::NotifyFindReply(int request_id,
+                                      int number_of_matches,
+                                      const gfx::Rect& selection_rect,
+                                      int active_match_ordinal,
+                                      bool final_update) {
+  if (delegate_) {
+    delegate_->FindReply(this, request_id, number_of_matches, selection_rect,
+                         active_match_ordinal, final_update);
+  }
+}
+
+#if defined(OS_ANDROID)
+void WebContentsImpl::NotifyFindMatchRectsReply(
+    int version,
+    const std::vector<gfx::RectF>& rects,
+    const gfx::RectF& active_rect) {
+  if (delegate_)
+    delegate_->FindMatchRectsReply(this, version, rects, active_rect);
+}
+#endif
+
 void WebContentsImpl::SetForceDisableOverscrollContent(bool force_disable) {
   force_disable_overscroll_content_ = force_disable;
   if (view_)
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index a08a0ff6..e136c08 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -56,6 +56,7 @@
 class BrowserPluginGuest;
 class DateTimeChooserAndroid;
 class DownloadItem;
+class FindRequestManager;
 class GeolocationServiceContext;
 class InterstitialPageImpl;
 class JavaScriptDialogManager;
@@ -385,6 +386,8 @@
 #if defined(OS_ANDROID)
   base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() override;
   virtual WebContentsAndroid* GetWebContentsAndroid();
+  void ActivateNearestFindResult(float x, float y) override;
+  void RequestFindMatchRects(int current_version) override;
 #elif defined(OS_MACOSX)
   void SetAllowOtherViews(bool allow) override;
   bool GetAllowOtherViews() override;
@@ -729,7 +732,22 @@
   // Update the web contents visibility.
   void UpdateWebContentsVisibility(bool visible);
 
- private:
+  // Called by FindRequestManager when find replies come in from a renderer
+  // process.
+  void NotifyFindReply(int request_id,
+                       int number_of_matches,
+                       const gfx::Rect& selection_rect,
+                       int active_match_ordinal,
+                       bool final_update);
+
+#if defined(OS_ANDROID)
+  // Called by FindRequestManager when all of the find match rects are in.
+  void NotifyFindMatchRectsReply(int version,
+                                 const std::vector<gfx::RectF>& rects,
+                                 const gfx::RectF& active_rect);
+#endif
+
+private:
   friend class WebContentsObserver;
   friend class WebContents;  // To implement factory methods.
 
@@ -789,7 +807,7 @@
     }
 
    private:
-    // The outer Webontents.
+    // The outer WebContents.
     WebContentsImpl* outer_web_contents_;
     // The ID of the FrameTreeNode in outer WebContents that is hosting us.
     int outer_contents_frame_tree_node_id_;
@@ -887,7 +905,7 @@
   void OnFindMatchRectsReply(int version,
                              const std::vector<gfx::RectF>& rects,
                              const gfx::RectF& active_rect);
-
+  void OnGetNearestFindResultReply(int request_id, float distance);
   void OnOpenDateTimeDialog(
       const ViewHostMsg_DateTimeDialogValue_Params& value);
 #endif
@@ -1041,6 +1059,9 @@
   void SetJavaScriptDialogManagerForTesting(
       JavaScriptDialogManager* dialog_manager);
 
+  // Returns the FindRequestManager, or creates one if it doesn't already exist.
+  FindRequestManager* GetOrCreateFindRequestManager();
+
   // Data for core operation ---------------------------------------------------
 
   // Delegate for notifying our owner about stuff. Not owned by us.
@@ -1092,6 +1113,9 @@
   // SavePackage, lazily created.
   scoped_refptr<SavePackage> save_package_;
 
+  // Manages/coordinates find-in-page requests. Created lazily.
+  scoped_ptr<FindRequestManager> find_request_manager_;
+
   // Data for loading state ----------------------------------------------------
 
   // Indicates whether the current load is to a different document. Only valid
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index ee96ebc..9ff78fe 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -203,12 +203,12 @@
     "//ui/accessibility",
     "//ui/base",
     "//ui/base/ime",
-    "//ui/events/ipc",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gfx/ipc",
     "//ui/gfx/ipc/skia",
     "//ui/gl",
+    "//ui/latency_info/ipc",
     "//ui/shell_dialogs",
     "//url",
     "//url/ipc:url_ipc",
@@ -315,7 +315,6 @@
       "pepper_renderer_instance_data.h",
       "plugin_list.cc",
       "plugin_list.h",
-      "sandbox_util.cc",
     ]
   }
 
diff --git a/content/common/accelerated_surface_buffers_swapped_params_mac.h b/content/common/accelerated_surface_buffers_swapped_params_mac.h
index 71fb4ff..a25a41a 100644
--- a/content/common/accelerated_surface_buffers_swapped_params_mac.h
+++ b/content/common/accelerated_surface_buffers_swapped_params_mac.h
@@ -6,8 +6,8 @@
 #define CONTENT_COMMON_ACCELERATED_SURFACE_BUFFERS_SWAPPED_PARAMS_MAC_H_
 
 #include "ui/base/cocoa/remote_layer_api.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/mac/io_surface.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 7d1f562..43dce9b4 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -1237,8 +1237,7 @@
 
 // Initial drawing parameters for a child frame that has been swapped out to
 // another process.
-IPC_MESSAGE_ROUTED2(FrameHostMsg_InitializeChildFrame,
-                    gfx::Rect /* frame_rect */,
+IPC_MESSAGE_ROUTED1(FrameHostMsg_InitializeChildFrame,
                     float /* scale_factor */)
 
 // Response for FrameMsg_JavaScriptExecuteRequest, sent when a reply was
diff --git a/content/common/gpu_host_messages.h b/content/common/gpu_host_messages.h
index 0705be0..d9c7846 100644
--- a/content/common/gpu_host_messages.h
+++ b/content/common/gpu_host_messages.h
@@ -20,10 +20,10 @@
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
 #include "ipc/ipc_message_start.h"
-#include "ui/events/ipc/latency_info_param_traits.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
 #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
+#include "ui/latency_info/ipc/latency_info_param_traits.h"
 #include "url/gurl.h"
 #include "url/ipc/url_param_traits.h"
 
diff --git a/content/common/input/event_with_latency_info.h b/content/common/input/event_with_latency_info.h
index 24742a3..55383876 100644
--- a/content/common/input/event_with_latency_info.h
+++ b/content/common/input/event_with_latency_info.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_COMMON_INPUT_EVENT_WITH_LATENCY_INFO_H_
 #define CONTENT_COMMON_INPUT_EVENT_WITH_LATENCY_INFO_H_
 
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 #include "content/common/input/web_input_event_traits.h"
 
diff --git a/content/common/input/input_event.h b/content/common/input/input_event.h
index 58485e13..6f3dc1b8 100644
--- a/content/common/input/input_event.h
+++ b/content/common/input/input_event.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "content/common/content_export.h"
 #include "content/common/input/scoped_web_input_event.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace blink {
 class WebInputEvent;
diff --git a/content/common/input/input_event_ack.h b/content/common/input/input_event_ack.h
index 565b66f..f7510d967 100644
--- a/content/common/input/input_event_ack.h
+++ b/content/common/input/input_event_ack.h
@@ -13,7 +13,7 @@
 #include "content/common/input/did_overscroll_params.h"
 #include "content/common/input/input_event_ack_state.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index e83a77b..2a4b521 100644
--- a/content/common/input_messages.h
+++ b/content/common/input_messages.h
@@ -27,13 +27,13 @@
 #include "content/common/input/touch_action.h"
 #include "ipc/ipc_message_macros.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/ipc/latency_info_param_traits.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/vector2d_f.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
 #include "ui/gfx/ipc/skia/gfx_skia_param_traits.h"
 #include "ui/gfx/range/range.h"
+#include "ui/latency_info/ipc/latency_info_param_traits.h"
 
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CONTENT_EXPORT
diff --git a/content/common/mojo/current_thread_loader.cc b/content/common/mojo/current_thread_loader.cc
deleted file mode 100644
index 561f91b1..0000000
--- a/content/common/mojo/current_thread_loader.cc
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/mojo/current_thread_loader.h"
-
-#include "base/memory/ptr_util.h"
-
-namespace content {
-
-CurrentThreadLoader::CurrentThreadLoader(const ApplicationFactory& factory)
-    : factory_(factory) {}
-
-CurrentThreadLoader::~CurrentThreadLoader() {}
-
-void CurrentThreadLoader::Load(const std::string& name,
-                               mojo::shell::mojom::ShellClientRequest request) {
-  if (!shell_client_) {
-    shell_client_ = factory_.Run();
-    factory_ = ApplicationFactory();
-  }
-
-  connections_.push_back(base::WrapUnique(
-      new mojo::ShellConnection(shell_client_.get(), std::move(request))));
-}
-
-}  // namespace content
diff --git a/content/common/mojo/current_thread_loader.h b/content/common/mojo/current_thread_loader.h
deleted file mode 100644
index ea2b370..0000000
--- a/content/common/mojo/current_thread_loader.h
+++ /dev/null
@@ -1,47 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_
-#define CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_
-
-#include <vector>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "services/shell/loader.h"
-#include "services/shell/public/cpp/shell_client.h"
-#include "services/shell/public/cpp/shell_connection.h"
-
-namespace content {
-
-// A Loader which loads a single type of app from a mojo::ShellClientFactory on
-// the current thread.
-class CurrentThreadLoader : public mojo::shell::Loader {
- public:
-  using ApplicationFactory =
-      base::Callback<std::unique_ptr<mojo::ShellClient>()>;
-
-  explicit CurrentThreadLoader(const ApplicationFactory& factory);
-  ~CurrentThreadLoader() override;
-
-  // mojo::shell::Loader:
-  void Load(const std::string& name,
-            mojo::shell::mojom::ShellClientRequest request) override;
-
- private:
-  // The factory used to create new instances of the application delegate. This
-  // is called exactly once since all connections share a single client.
-  ApplicationFactory factory_;
-
-  // Our shared shell client, passed to each connection.
-  std::unique_ptr<mojo::ShellClient> shell_client_;
-
-  std::vector<std::unique_ptr<mojo::ShellConnection>> connections_;
-
-  DISALLOW_COPY_AND_ASSIGN(CurrentThreadLoader);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_MOJO_CURRENT_THREAD_LOADER_H_
diff --git a/content/common/mojo/embedded_application_runner.cc b/content/common/mojo/embedded_application_runner.cc
new file mode 100644
index 0000000..73b5d326
--- /dev/null
+++ b/content/common/mojo/embedded_application_runner.cc
@@ -0,0 +1,90 @@
+// 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 "content/common/mojo/embedded_application_runner.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/thread_task_runner_handle.h"
+#include "base/threading/thread_checker.h"
+#include "services/shell/public/cpp/shell_connection.h"
+
+namespace content {
+
+class EmbeddedApplicationRunner::Instance
+    : public base::RefCountedThreadSafe<Instance> {
+ public:
+  explicit Instance(
+      const EmbeddedApplicationRunner::FactoryCallback& callback)
+      : factory_callback_(callback) {
+    // This object may be used exclusively from a single thread which may be
+    // different from the one that created it.
+    thread_checker_.DetachFromThread();
+  }
+
+  void BindShellClientRequest(mojo::shell::mojom::ShellClientRequest request) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    if (!shell_client_)
+      shell_client_ = factory_callback_.Run();
+
+    std::unique_ptr<mojo::ShellConnection> new_connection(
+        new mojo::ShellConnection(shell_client_.get(), std::move(request)));
+    new_connection->set_connection_lost_closure(
+        base::Bind(&Instance::OnShellConnectionLost,
+                   base::Unretained(this), new_connection.get()));
+    shell_connections_.push_back(std::move(new_connection));
+  }
+
+ private:
+  friend class base::RefCountedThreadSafe<Instance>;
+
+  ~Instance() { DCHECK(thread_checker_.CalledOnValidThread()); }
+
+  void OnShellConnectionLost(mojo::ShellConnection* connection) {
+    DCHECK(thread_checker_.CalledOnValidThread());
+
+    for (auto it = shell_connections_.begin(); it != shell_connections_.end();
+         ++it) {
+      if (it->get() == connection) {
+        shell_connections_.erase(it);
+        break;
+      }
+    }
+
+    if (shell_connections_.empty())
+      shell_client_.reset();
+  }
+
+  base::ThreadChecker thread_checker_;
+  const FactoryCallback factory_callback_;
+  std::unique_ptr<mojo::ShellClient> shell_client_;
+  std::vector<std::unique_ptr<mojo::ShellConnection>> shell_connections_;
+
+  DISALLOW_COPY_AND_ASSIGN(Instance);
+};
+
+EmbeddedApplicationRunner::EmbeddedApplicationRunner(
+    const FactoryCallback& callback,
+    const scoped_refptr<base::SingleThreadTaskRunner>& task_runner)
+    : application_task_runner_(
+          task_runner ? task_runner : base::ThreadTaskRunnerHandle::Get()),
+      instance_(new Instance(callback)) {
+}
+
+EmbeddedApplicationRunner::~EmbeddedApplicationRunner() {
+}
+
+void EmbeddedApplicationRunner::BindShellClientRequest(
+    mojo::shell::mojom::ShellClientRequest request) {
+  application_task_runner_->PostTask(
+      FROM_HERE,
+      base::Bind(&Instance::BindShellClientRequest, instance_,
+                 base::Passed(&request)));
+}
+
+}  // namespace content
diff --git a/content/common/mojo/embedded_application_runner.h b/content/common/mojo/embedded_application_runner.h
new file mode 100644
index 0000000..8c5aa855
--- /dev/null
+++ b/content/common/mojo/embedded_application_runner.h
@@ -0,0 +1,61 @@
+// 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 CONTENT_COMMON_MOJO_EMBEDDED_APPLICATION_RUNNER_H_
+#define CONTENT_COMMON_MOJO_EMBEDDED_APPLICATION_RUNNER_H_
+
+#include <memory>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/single_thread_task_runner.h"
+#include "services/shell/public/cpp/shell_client.h"
+#include "services/shell/public/interfaces/shell_client.mojom.h"
+
+namespace content {
+
+// Hosts an in-process application instance that supports multiple ShellClient
+// connections. The first incoming connection will invoke a provided factory
+// function to instantiate the application, and the application will
+// automatically be torn down when its last connection is lost. The application
+// may be launched and torn down multiple times by a single
+// EmbeddedApplicationRunner instance.
+class EmbeddedApplicationRunner {
+ public:
+  using FactoryCallback =
+      base::Callback<std::unique_ptr<mojo::ShellClient>()>;
+
+  // Constructs a runner which hosts the application on |task_runner|'s thread.
+  // If an existing instance of the app is not running when an incoming
+  // connection is made, |callback| will be run on |task_runner|'s thread to
+  // create a new instance which will live on that thread.
+  EmbeddedApplicationRunner(
+      const FactoryCallback& callback,
+      const scoped_refptr<base::SingleThreadTaskRunner>& task_runner);
+
+  ~EmbeddedApplicationRunner();
+
+  // Binds an incoming ShellClientRequest for this application. If the
+  // application isn't already running, it's started. Otherwise the request is
+  // bound to the running instance.
+  void BindShellClientRequest(mojo::shell::mojom::ShellClientRequest request);
+
+ private:
+  class Instance;
+
+  // The TaskRunner on which the factory callback will be run. The
+  // mojo::ShellClient it returns will live and die on this TaskRunner's thread.
+  const scoped_refptr<base::SingleThreadTaskRunner> application_task_runner_;
+
+  // A reference to the application instance which may operate on the
+  // |application_task_runner_|'s thread.
+  scoped_refptr<Instance> instance_;
+
+  DISALLOW_COPY_AND_ASSIGN(EmbeddedApplicationRunner);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MOJO_EMBEDDED_APPLICATION_RUNNER_H_
diff --git a/content/common/sandbox_util.cc b/content/common/sandbox_util.cc
deleted file mode 100644
index 75b3977f..0000000
--- a/content/common/sandbox_util.cc
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/common/sandbox_util.h"
-
-#include "build/build_config.h"
-#include "content/public/common/sandbox_init.h"
-#include "ipc/ipc_platform_file.h"
-
-#if defined(OS_POSIX)
-#include <unistd.h>
-#endif
-
-namespace content {
-
-IPC::PlatformFileForTransit BrokerGetFileHandleForProcess(
-    base::PlatformFile handle,
-    base::ProcessId target_process_id,
-    bool should_close_source) {
-  return IPC::GetPlatformFileForTransit(handle, should_close_source);
-}
-
-}  // namespace content
-
diff --git a/content/common/sandbox_util.h b/content/common/sandbox_util.h
deleted file mode 100644
index 54814df..0000000
--- a/content/common/sandbox_util.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_SANDBOX_UTIL_H_
-#define CONTENT_COMMON_SANDBOX_UTIL_H_
-
-#include "base/process/process.h"
-#include "ipc/ipc_platform_file.h"
-
-// This file contains cross-platform sandbox code internal to content.
-
-namespace content {
-
-// Platform neutral wrapper for making an exact copy of a handle for use in
-// the target process. On Windows this wraps BrokerDuplicateHandle() with the
-// DUPLICATE_SAME_ACCESS flag. On posix it behaves essentially the same as
-// IPC::GetFileHandleForProcess()
-IPC::PlatformFileForTransit BrokerGetFileHandleForProcess(
-    base::PlatformFile handle,
-    base::ProcessId target_process_id,
-    bool should_close_source);
-
-}  // namespace content
-
-#endif  // CONTENT_COMMON_SANDBOX_UTIL_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index efcc6e5f..a3a96ad 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -10,6 +10,7 @@
     '../components/leveldb/leveldb.gyp:leveldb_lib',
     '../components/mime_util/mime_util.gyp:mime_util',
     '../components/profile_service/profile_service.gyp:profile_service_lib',
+    '../components/profile_service/profile_service.gyp:profile_service_public_lib',
     '../components/scheduler/scheduler.gyp:scheduler_common',
     '../components/url_formatter/url_formatter.gyp:url_formatter',
     '../crypto/crypto.gyp:crypto',
@@ -63,6 +64,7 @@
     '../ui/events/events.gyp:gesture_detection',
     '../ui/gfx/gfx.gyp:gfx',
     '../ui/gfx/gfx.gyp:gfx_geometry',
+    '../ui/latency_info/latency_info.gyp:latency_info',
     '../ui/resources/ui_resources.gyp:ui_resources',
     '../ui/snapshot/snapshot.gyp:snapshot',
     '../ui/surface/surface.gyp:surface',
@@ -738,6 +740,8 @@
       'browser/fileapi/fileapi_message_filter.h',
       'browser/fileapi/upload_file_system_file_element_reader.cc',
       'browser/fileapi/upload_file_system_file_element_reader.h',
+      'browser/find_request_manager.cc',
+      'browser/find_request_manager.h',
       'browser/font_list_async.cc',
       'browser/frame_host/cross_process_frame_connector.cc',
       'browser/frame_host/cross_process_frame_connector.h',
@@ -1120,6 +1124,8 @@
       'browser/message_port_service.h',
       'browser/mime_registry_message_filter.cc',
       'browser/mime_registry_message_filter.h',
+      'browser/mojo/browser_shell_connection.cc',
+      'browser/mojo/browser_shell_connection.h',
       'browser/mojo/constants.cc',
       'browser/mojo/constants.h',
       'browser/mojo/mojo_app_connection_impl.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index 1ae5f116..c4a59dfa 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -45,7 +45,7 @@
     '../ui/accessibility/accessibility.gyp:ax_gen',
     '../ui/base/ime/ui_base_ime.gyp:ui_base_ime',
     '../ui/base/ui_base.gyp:ui_base',
-    '../ui/events/events.gyp:events_ipc',
+    '../ui/latency_info/latency_info.gyp:latency_info_ipc',
     '../ui/gfx/gfx.gyp:gfx',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
@@ -463,8 +463,8 @@
       'common/mime_registry_messages.h',
       'common/mojo/channel_init.cc',
       'common/mojo/channel_init.h',
-      'common/mojo/current_thread_loader.cc',
-      'common/mojo/current_thread_loader.h',
+      'common/mojo/embedded_application_runner.cc',
+      'common/mojo/embedded_application_runner.h',
       'common/mojo/mojo_messages.h',
       'common/mojo/mojo_shell_connection_impl.cc',
       'common/mojo/mojo_shell_connection_impl.h',
@@ -539,8 +539,6 @@
       'common/sandbox_linux/sandbox_seccomp_bpf_linux.h',
       'common/sandbox_mac.h',
       'common/sandbox_mac.mm',
-      'common/sandbox_util.cc',
-      'common/sandbox_util.h',
       'common/sandbox_win.cc',
       'common/sandbox_win.h',
       'common/savable_subframe.h',
@@ -707,7 +705,6 @@
         'common/pepper_renderer_instance_data.h',
         'common/plugin_list.cc',
         'common/plugin_list.h',
-        'common/sandbox_util.cc',
         'public/common/pepper_plugin_info.cc',
         'public/common/pepper_plugin_info.h',
       ],
diff --git a/content/content_resources.grd b/content/content_resources.grd
index c7692b6..20c7d2d 100644
--- a/content/content_resources.grd
+++ b/content/content_resources.grd
@@ -30,6 +30,7 @@
       <include name="IDR_MOJO_CATALOG_MANIFEST" file="../services/catalog/manifest.json" type="BINDATA" />
       <include name="IDR_MOJO_CONTENT_BROWSER_MANIFEST" file="${root_out_dir}/content_browser_manifest.json" use_base_dir="false" type="BINDATA" />
       <include name="IDR_MOJO_CONTENT_RENDERER_MANIFEST" file="${root_out_dir}/content_renderer_manifest.json" use_base_dir="false" type="BINDATA" />
+      <include name="IDR_MOJO_PROFILE_MANIFEST" file="../components/profile_service/manifest.json" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_HTML" file="browser/resources/net/network_errors_listing.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_JS" file="browser/resources/net/network_errors_listing.js" flattenhtml="true" type="BINDATA" />
       <include name="IDR_NETWORK_ERROR_LISTING_CSS" file="browser/resources/net/network_errors_listing.css" flattenhtml="true" type="BINDATA" />
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index 00adfe5..4399cbb1 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -870,6 +870,7 @@
         '../ui/events/events.gyp:events_test_support',
         '../ui/events/events.gyp:gesture_detection',
         '../ui/gfx/gfx.gyp:gfx_test_support',
+        '../ui/latency_info/latency_info.gyp:latency_info',
         '../ui/resources/ui_resources.gyp:ui_resources',
         '../ui/surface/surface.gyp:surface',
         '../url/url.gyp:url_lib',
diff --git a/content/gpu/BUILD.gn b/content/gpu/BUILD.gn
index 75ea4c58..35fc15e 100644
--- a/content/gpu/BUILD.gn
+++ b/content/gpu/BUILD.gn
@@ -56,9 +56,9 @@
     "//media/mojo/services:application_factory",
     "//services/shell/public/interfaces",
     "//skia",
-    "//ui/events/ipc",
     "//ui/gfx/ipc",
     "//ui/gl",
+    "//ui/latency_info/ipc",
   ]
 
   if (mojo_media_host == "gpu") {
diff --git a/content/ppapi_plugin/ppapi_thread.cc b/content/ppapi_plugin/ppapi_thread.cc
index 8e0724b..469fb784 100644
--- a/content/ppapi_plugin/ppapi_thread.cc
+++ b/content/ppapi_plugin/ppapi_thread.cc
@@ -28,7 +28,6 @@
 #include "content/child/child_discardable_shared_memory_manager.h"
 #include "content/child/child_process.h"
 #include "content/common/child_process_messages.h"
-#include "content/common/sandbox_util.h"
 #include "content/ppapi_plugin/broker_process_dispatcher.h"
 #include "content/ppapi_plugin/plugin_process_dispatcher.h"
 #include "content/ppapi_plugin/ppapi_blink_platform_impl.h"
@@ -192,15 +191,7 @@
     base::PlatformFile handle,
     base::ProcessId peer_pid,
     bool should_close_source) {
-#if defined(OS_WIN)
-  if (peer_handle_.IsValid()) {
-    DCHECK(is_broker_);
-    return IPC::GetPlatformFileForTransit(handle, should_close_source);
-  }
-#endif
-
-  DCHECK(peer_pid != base::kNullProcessId);
-  return BrokerGetFileHandleForProcess(handle, peer_pid, should_close_source);
+  return IPC::GetPlatformFileForTransit(handle, should_close_source);
 }
 
 base::SharedMemoryHandle PpapiThread::ShareSharedMemoryHandleWithRemote(
diff --git a/content/public/app/BUILD.gn b/content/public/app/BUILD.gn
index 5fe6249..97ede77 100644
--- a/content/public/app/BUILD.gn
+++ b/content/public/app/BUILD.gn
@@ -146,6 +146,10 @@
   type = "exe"
   application_name = "content_browser"
   source = "mojo/content_browser_manifest.json"
+  packaged_applications = [ "profile" ]
+  deps = [
+    "//components/profile_service:manifest",
+  ]
 }
 
 mojo_application_manifest("renderer_manifest") {
diff --git a/content/public/app/mojo/content_browser_manifest.json b/content/public/app/mojo/content_browser_manifest.json
index 96ff473..c560fdc 100644
--- a/content/public/app/mojo/content_browser_manifest.json
+++ b/content/public/app/mojo/content_browser_manifest.json
@@ -1,12 +1,13 @@
 {
   "manifest_version": 1,
   "name": "exe:content_browser",
+  "process-group": "browser",
   "display_name": "Content Browser",
   "capabilities": {
     "required": {
       "*": { "interfaces": [ "*" ] },
       "mojo:shell": {
-        "classes": [ "client_process", "instance_name" ],
+        "classes": [ "client_process", "instance_name", "user_id" ],
         "interfaces": [ "*" ]
       }
     }
diff --git a/content/public/browser/browser_context.h b/content/public/browser/browser_context.h
index a218f40..af0f332d 100644
--- a/content/public/browser/browser_context.h
+++ b/content/public/browser/browser_context.h
@@ -30,6 +30,10 @@
 class Time;
 }
 
+namespace mojo {
+class Connector;
+}
+
 namespace storage {
 class ExternalMountPoints;
 }
@@ -152,6 +156,10 @@
   // services/shell/public/interfaces/connector.mojom.
   static const std::string& GetMojoUserIdFor(BrowserContext* browser_context);
 
+  // Returns a Connector associated with this BrowserContext, which can be used
+  // to connect to Mojo application instances bound to a specific user.
+  static mojo::Connector* GetMojoConnectorFor(BrowserContext* browser_context);
+
   ~BrowserContext() override;
 
   // Creates a delegate to initialize a HostZoomMap and persist its information.
diff --git a/content/public/browser/render_frame_host.h b/content/public/browser/render_frame_host.h
index b8fa796..86ac9d5 100644
--- a/content/public/browser/render_frame_host.h
+++ b/content/public/browser/render_frame_host.h
@@ -191,15 +191,6 @@
   // use by resource metrics.
   virtual int GetProxyCount() = 0;
 
-#if defined(OS_ANDROID)
-  // Selects and zooms to the find result nearest to the point (x,y)
-  // defined in find-in-page coordinates.
-  virtual void ActivateNearestFindResult(int request_id, float x, float y) = 0;
-
-  // Asks the renderer process to send the rects of the current find matches.
-  virtual void RequestFindMatchRects(int current_version) = 0;
-#endif
-
  private:
   // This interface should only be implemented inside content.
   friend class RenderFrameHostImpl;
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h
index 94ee37dd4..eb0da0053 100644
--- a/content/public/browser/web_contents.h
+++ b/content/public/browser/web_contents.h
@@ -708,6 +708,20 @@
   CONTENT_EXPORT static WebContents* FromJavaWebContents(
       jobject jweb_contents_android);
   virtual base::android::ScopedJavaLocalRef<jobject> GetJavaWebContents() = 0;
+
+  // Selects and zooms to the find result nearest to the point (x,y) defined in
+  // find-in-page coordinates.
+  virtual void ActivateNearestFindResult(float x, float y) = 0;
+
+  // Requests the rects of the current find matches from the renderer
+  // process. |current_version| is the version of find rects that the caller
+  // already knows about. This version will be compared to the current find
+  // rects version in the renderer process (which is updated whenever the rects
+  // change), to see which new rect data will need to be sent back.
+  //
+  // TODO(paulmeyer): This process will change slightly once multi-process
+  // find-in-page is implemented. This comment should be updated at that time.
+  virtual void RequestFindMatchRects(int current_version) = 0;
 #elif defined(OS_MACOSX)
   // Allowing other views disables optimizations which assume that only a single
   // WebContents is present.
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index 0fc10f6..a76aa30 100644
--- a/content/public/test/browser_test_utils.cc
+++ b/content/public/test/browser_test_utils.cc
@@ -59,7 +59,7 @@
 #include "ui/events/gesture_detection/gesture_configuration.h"
 #include "ui/events/keycodes/dom/dom_code.h"
 #include "ui/events/keycodes/dom/keycode_converter.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 #include "ui/resources/grit/webui_resources.h"
 
 #if defined(USE_AURA)
diff --git a/content/renderer/android/synchronous_compositor_proxy.cc b/content/renderer/android/synchronous_compositor_proxy.cc
index 4b1eaca..a0d4daf7 100644
--- a/content/renderer/android/synchronous_compositor_proxy.cc
+++ b/content/renderer/android/synchronous_compositor_proxy.cc
@@ -16,8 +16,8 @@
 #include "third_party/skia/include/core/SkCanvas.h"
 #include "third_party/skia/include/core/SkImageInfo.h"
 #include "third_party/skia/include/core/SkRegion.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/skia_util.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/renderer/input/main_thread_event_queue.h b/content/renderer/input/main_thread_event_queue.h
index 0eb2d147..02f7d8d6 100644
--- a/content/renderer/input/main_thread_event_queue.h
+++ b/content/renderer/input/main_thread_event_queue.h
@@ -12,7 +12,7 @@
 #include "content/common/input/input_event_dispatch_type.h"
 #include "content/common/input/web_input_event_queue.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace content {
 
diff --git a/content/renderer/input/render_widget_input_handler.cc b/content/renderer/input/render_widget_input_handler.cc
index e407428..7914eea0 100644
--- a/content/renderer/input/render_widget_input_handler.cc
+++ b/content/renderer/input/render_widget_input_handler.cc
@@ -26,8 +26,8 @@
 #include "content/renderer/render_widget.h"
 #include "third_party/WebKit/public/platform/WebFloatPoint.h"
 #include "third_party/WebKit/public/platform/WebFloatSize.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/point_conversions.h"
+#include "ui/latency_info/latency_info.h"
 
 #if defined(OS_ANDROID)
 #include <android/keycodes.h>
diff --git a/content/renderer/media/media_stream_audio_processor_options.cc b/content/renderer/media/media_stream_audio_processor_options.cc
index 9020be04..9d13b1a 100644
--- a/content/renderer/media/media_stream_audio_processor_options.cc
+++ b/content/renderer/media/media_stream_audio_processor_options.cc
@@ -448,6 +448,8 @@
     stats->echo_return_loss = echo_metrics.echo_return_loss.instant;
     stats->echo_return_loss_enhancement =
         echo_metrics.echo_return_loss_enhancement.instant;
+    stats->aec_divergent_filter_fraction =
+        echo_metrics.divergent_filter_fraction;
   }
 
   int median = 0, std = 0;
diff --git a/content/renderer/mus/BUILD.gn b/content/renderer/mus/BUILD.gn
index c2d3f93..326748f 100644
--- a/content/renderer/mus/BUILD.gn
+++ b/content/renderer/mus/BUILD.gn
@@ -33,5 +33,6 @@
     "//third_party/WebKit/public:blink",
     "//ui/events:events",
     "//ui/events:events_base",
+    "//ui/latency_info",
   ]
 }
diff --git a/content/renderer/mus/compositor_mus_connection.cc b/content/renderer/mus/compositor_mus_connection.cc
index 57cdb76d..0ae3a84e 100644
--- a/content/renderer/mus/compositor_mus_connection.cc
+++ b/content/renderer/mus/compositor_mus_connection.cc
@@ -10,7 +10,7 @@
 #include "content/renderer/mus/render_widget_mus_connection.h"
 #include "mojo/converters/blink/blink_input_events_type_converters.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace {
 
diff --git a/content/renderer/pepper/host_array_buffer_var.cc b/content/renderer/pepper/host_array_buffer_var.cc
index 4d8a9212..a4899c3 100644
--- a/content/renderer/pepper/host_array_buffer_var.cc
+++ b/content/renderer/pepper/host_array_buffer_var.cc
@@ -13,7 +13,6 @@
 #include "base/memory/shared_memory.h"
 #include "base/process/process_handle.h"
 #include "content/common/pepper_file_util.h"
-#include "content/common/sandbox_util.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/plugin_module.h"
 #include "content/renderer/pepper/renderer_ppapi_host_impl.h"
diff --git a/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc b/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
index 9b03415..c97d6a5 100644
--- a/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
+++ b/content/renderer/pepper/pepper_proxy_channel_delegate_impl.cc
@@ -6,11 +6,7 @@
 
 #include "build/build_config.h"
 #include "content/child/child_process.h"
-#include "content/common/sandbox_util.h"
-
-#if defined(OS_WIN) || defined(OS_MACOSX)
-#include "content/public/common/sandbox_init.h"
-#endif  // defined(OS_WIN) || defined(OS_MACOSX)
+#include "ipc/ipc_platform_file.h"
 
 namespace content {
 
@@ -33,7 +29,7 @@
     base::PlatformFile handle,
     base::ProcessId remote_pid,
     bool should_close_source) {
-  return BrokerGetFileHandleForProcess(handle, remote_pid, should_close_source);
+  return IPC::GetPlatformFileForTransit(handle, should_close_source);
 }
 
 base::SharedMemoryHandle
diff --git a/content/renderer/pepper/renderer_ppapi_host_impl.cc b/content/renderer/pepper/renderer_ppapi_host_impl.cc
index e694406..15589f7 100644
--- a/content/renderer/pepper/renderer_ppapi_host_impl.cc
+++ b/content/renderer/pepper/renderer_ppapi_host_impl.cc
@@ -11,7 +11,6 @@
 #include "base/process/process_handle.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
-#include "content/common/sandbox_util.h"
 #include "content/renderer/pepper/fullscreen_container.h"
 #include "content/renderer/pepper/host_globals.h"
 #include "content/renderer/pepper/pepper_browser_connection.h"
@@ -23,6 +22,7 @@
 #include "content/renderer/render_view_impl.h"
 #include "content/renderer/render_widget_fullscreen_pepper.h"
 #include "ipc/ipc_message.h"
+#include "ipc/ipc_platform_file.h"
 #include "ppapi/host/ppapi_host.h"
 #include "ppapi/proxy/host_dispatcher.h"
 #include "third_party/WebKit/public/platform/WebRect.h"
@@ -225,8 +225,7 @@
     // Duplicate the file handle for in process mode so this function
     // has the same semantics for both in process mode and out of
     // process mode (i.e., the remote side must cloes the handle).
-    return BrokerGetFileHandleForProcess(
-        handle, base::GetCurrentProcId(), should_close_source);
+    return IPC::GetPlatformFileForTransit(handle, should_close_source);
   }
   return dispatcher_->ShareHandleWithRemote(handle, should_close_source);
 }
diff --git a/content/renderer/render_frame_proxy.cc b/content/renderer/render_frame_proxy.cc
index d9019937..0b550b9 100644
--- a/content/renderer/render_frame_proxy.cc
+++ b/content/renderer/render_frame_proxy.cc
@@ -416,10 +416,9 @@
 }
 
 void RenderFrameProxy::initializeChildFrame(
-    const blink::WebRect& frame_rect,
     float scale_factor) {
   Send(new FrameHostMsg_InitializeChildFrame(
-      routing_id_, frame_rect, scale_factor));
+      routing_id_, scale_factor));
 }
 
 void RenderFrameProxy::navigate(const blink::WebURLRequest& request,
diff --git a/content/renderer/render_frame_proxy.h b/content/renderer/render_frame_proxy.h
index 5fd375c..3ccbd9b 100644
--- a/content/renderer/render_frame_proxy.h
+++ b/content/renderer/render_frame_proxy.h
@@ -128,8 +128,7 @@
                         blink::WebRemoteFrame* targetFrame,
                         blink::WebSecurityOrigin target,
                         blink::WebDOMMessageEvent event) override;
-  void initializeChildFrame(const blink::WebRect& frame_rect,
-                            float scale_factor) override;
+  void initializeChildFrame(float scale_factor) override;
   void navigate(const blink::WebURLRequest& request,
                 bool should_replace_current_entry) override;
   void forwardInputEvent(const blink::WebInputEvent* event) override;
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index cc7ce3c5..d25ebf1 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -169,12 +169,12 @@
 #include "third_party/icu/source/common/unicode/uscript.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/ui_base_switches_util.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 #include "ui/gfx/native_widget_types.h"
+#include "ui/latency_info/latency_info.h"
 #include "url/url_constants.h"
 #include "v8/include/v8.h"
 
diff --git a/content/test/data/media/session/media-session.html b/content/test/data/media/session/media-session.html
index e1df282..46a7deae 100644
--- a/content/test/data/media/session/media-session.html
+++ b/content/test/data/media/session/media-session.html
@@ -27,10 +27,4 @@
     <source src='video-6seconds-silent.webm'>
   </video>
 </body>
-<script>
-  longVideo = document.getElementById("long-video");
-  longVideo.addEventListener("play", function(e) {
-
-  });
-</script>
 </html>
diff --git a/content/test/ppapi/ppapi_browsertest.cc b/content/test/ppapi/ppapi_browsertest.cc
index 75f93933..50ae717 100644
--- a/content/test/ppapi/ppapi_browsertest.cc
+++ b/content/test/ppapi/ppapi_browsertest.cc
@@ -151,7 +151,13 @@
 TEST_PPAPI_IN_PROCESS(VarResource)
 TEST_PPAPI_OUT_OF_PROCESS(VarResource)
 
-TEST_PPAPI_OUT_OF_PROCESS(VideoDecoder)
+// Flaky on Win, Linux and CrOS, http://crbug.com/602877
+#if defined(OS_WIN) || defined(OS_LINUX) || defined(OS_CHROMEOS)
+#define MAYBE_VideoDecoder DISABLED_VideoDecoder
+#else
+#define MAYBE_VideoDecoder VideoDecoder
+#endif
+TEST_PPAPI_OUT_OF_PROCESS(MAYBE_VideoDecoder)
 
 TEST_PPAPI_IN_PROCESS(VideoDecoderDev)
 TEST_PPAPI_OUT_OF_PROCESS(VideoDecoderDev)
diff --git a/extensions/browser/extension_function_histogram_value.h b/extensions/browser/extension_function_histogram_value.h
index f0d2d65f..3eaba42 100644
--- a/extensions/browser/extension_function_histogram_value.h
+++ b/extensions/browser/extension_function_histogram_value.h
@@ -1174,6 +1174,8 @@
   INPUTMETHODPRIVATE_SHOWINPUTVIEW,
   WALLPAPERPRIVATE_RECORDWALLPAPERUMA,
   AUTOTESTPRIVATE_GETVISIBLENOTIFICATIONS,
+  WEBRTCLOGGINGPRIVATE_STARTRTCEVENTLOGGING,
+  WEBRTCLOGGINGPRIVATE_STOPRTCEVENTLOGGING,
   // Last entry: Add new entries above, then run:
   // python tools/metrics/histograms/update_extension_histograms.py
   ENUM_BOUNDARY
diff --git a/extensions/browser/guest_view/web_view/web_view_find_helper.cc b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
index f9a315f6..caa082e 100644
--- a/extensions/browser/guest_view/web_view/web_view_find_helper.cc
+++ b/extensions/browser/guest_view/web_view/web_view_find_helper.cc
@@ -157,13 +157,13 @@
   DCHECK(current_find_session_);
 
   WebViewFindHelper::FindInfo* find_info = find_iterator->second.get();
-
   // Handle canceled find requests.
   if (!find_info->options()->findNext &&
       find_info_map_.begin()->first < request_id) {
     DCHECK_NE(current_find_session_->request_id(),
               find_info_map_.begin()->first);
-    DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
+    if (find_update_event_)
+      DispatchFindUpdateEvent(true /* canceled */, true /* final_update */);
     EndFindSession(find_info_map_.begin()->first, true /* canceled */);
   }
 
diff --git a/extensions/browser/guest_view/web_view/web_view_guest.h b/extensions/browser/guest_view/web_view/web_view_guest.h
index d1baac5..19391ac 100644
--- a/extensions/browser/guest_view/web_view/web_view_guest.h
+++ b/extensions/browser/guest_view/web_view/web_view_guest.h
@@ -24,7 +24,7 @@
 
 namespace blink {
 struct WebFindOptions;
-}  // nanespace blink
+}  // namespace blink
 
 namespace content {
 struct GlobalRequestID;
diff --git a/gpu/gpu_ipc_client.gypi b/gpu/gpu_ipc_client.gypi
index 6ca3c0e0..0aa89005 100644
--- a/gpu/gpu_ipc_client.gypi
+++ b/gpu/gpu_ipc_client.gypi
@@ -8,11 +8,11 @@
     '../ipc/ipc.gyp:ipc',
     '../third_party/khronos/khronos.gyp:khronos_headers',
     '../ui/base/ui_base.gyp:ui_base',
-    '../ui/events/events.gyp:events_base',
-    '../ui/events/events.gyp:events_ipc',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
     '../ui/gl/gl.gyp:gl',
+    '../ui/latency_info/latency_info.gyp:latency_info',
+    '../ui/latency_info/latency_info.gyp:latency_info_ipc',
     '../url/url.gyp:url_lib',
     '../url/ipc/url_ipc.gyp:url_ipc',
   ],
diff --git a/gpu/gpu_ipc_common.gypi b/gpu/gpu_ipc_common.gypi
index 9e9ea60..05e7c44b 100644
--- a/gpu/gpu_ipc_common.gypi
+++ b/gpu/gpu_ipc_common.gypi
@@ -8,11 +8,10 @@
     '../ipc/ipc.gyp:ipc',
     '../third_party/khronos/khronos.gyp:khronos_headers',
     '../ui/base/ui_base.gyp:ui_base',
-    '../ui/events/events.gyp:events_base',
-    '../ui/events/events.gyp:events_ipc',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
     '../ui/gl/gl.gyp:gl',
+    '../ui/latency_info/latency_info.gyp:latency_info_ipc',
     '../url/url.gyp:url_lib',
     '../url/ipc/url_ipc.gyp:url_ipc',
   ],
diff --git a/gpu/gpu_ipc_service.gypi b/gpu/gpu_ipc_service.gypi
index 8865814..8a8b63618 100644
--- a/gpu/gpu_ipc_service.gypi
+++ b/gpu/gpu_ipc_service.gypi
@@ -6,11 +6,10 @@
   'dependencies': [
     '../base/base.gyp:base',
     '../ipc/ipc.gyp:ipc',
-    '../ui/events/events.gyp:events_base',
-    '../ui/events/events.gyp:events_ipc',
     '../ui/gfx/gfx.gyp:gfx',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gl/gl.gyp:gl',
+    '../ui/latency_info/latency_info.gyp:latency_info_ipc',
     '../url/url.gyp:url_lib',
   ],
   'include_dirs': [
diff --git a/gpu/ipc/client/BUILD.gn b/gpu/ipc/client/BUILD.gn
index f77d1fe..2c0f88d 100644
--- a/gpu/ipc/client/BUILD.gn
+++ b/gpu/ipc/client/BUILD.gn
@@ -57,9 +57,9 @@
     "//gpu/config:config_sources",
     "//gpu/ipc/common:ipc_common_sources",
     "//ipc",
-    "//ui/events/ipc",
     "//ui/gfx/ipc",
     "//ui/gl",
+    "//ui/latency_info/ipc",
     "//url/ipc:url_ipc",
   ]
   if (use_ozone) {
diff --git a/gpu/ipc/client/DEPS b/gpu/ipc/client/DEPS
index 45e1d3de..e90ac2e 100644
--- a/gpu/ipc/client/DEPS
+++ b/gpu/ipc/client/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+base",
   "+ipc",
-  "+ui/events",
-  "+ui/base",
+  "+ui/latency_info",
 ]
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 89347bf..7a200de 100644
--- a/gpu/ipc/client/command_buffer_proxy_impl.h
+++ b/gpu/ipc/client/command_buffer_proxy_impl.h
@@ -27,8 +27,8 @@
 #include "gpu/command_buffer/common/gpu_memory_allocation.h"
 #include "gpu/gpu_export.h"
 #include "ipc/ipc_listener.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/swap_result.h"
+#include "ui/latency_info/latency_info.h"
 
 struct GPUCommandBufferConsoleMessage;
 
diff --git a/gpu/ipc/client/gpu_channel_host.h b/gpu/ipc/client/gpu_channel_host.h
index be04133..f2c27e1 100644
--- a/gpu/ipc/client/gpu_channel_host.h
+++ b/gpu/ipc/client/gpu_channel_host.h
@@ -27,10 +27,10 @@
 #include "ipc/ipc_sync_channel.h"
 #include "ipc/message_filter.h"
 #include "ipc/message_router.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gl/gpu_preference.h"
+#include "ui/latency_info/latency_info.h"
 
 class GURL;
 
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn
index c596e26..2c31f72 100644
--- a/gpu/ipc/common/BUILD.gn
+++ b/gpu/ipc/common/BUILD.gn
@@ -86,9 +86,9 @@
     "//gpu/command_buffer/common:common_sources",
     "//gpu/config:config_sources",
     "//ipc",
-    "//ui/events/ipc",
     "//ui/gfx/ipc",
     "//ui/gl",
+    "//ui/latency_info/ipc",
     "//url/ipc:url_ipc",
   ]
 
diff --git a/gpu/ipc/common/DEPS b/gpu/ipc/common/DEPS
index 45e1d3de..04878b14 100644
--- a/gpu/ipc/common/DEPS
+++ b/gpu/ipc/common/DEPS
@@ -1,6 +1,6 @@
 include_rules = [
   "+base",
   "+ipc",
-  "+ui/events",
   "+ui/base",
+  "+ui/latency_info",
 ]
diff --git a/gpu/ipc/common/gpu_messages.h b/gpu/ipc/common/gpu_messages.h
index 449d151..0e5ed72 100644
--- a/gpu/ipc/common/gpu_messages.h
+++ b/gpu/ipc/common/gpu_messages.h
@@ -26,13 +26,13 @@
 #include "gpu/ipc/common/surface_handle.h"
 #include "ipc/ipc_channel_handle.h"
 #include "ipc/ipc_message_macros.h"
-#include "ui/events/ipc/latency_info_param_traits.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/ipc/gfx_param_traits.h"
 #include "ui/gfx/native_widget_types.h"
 #include "ui/gfx/swap_result.h"
+#include "ui/latency_info/ipc/latency_info_param_traits.h"
+#include "ui/latency_info/latency_info.h"
 #include "url/ipc/url_param_traits.h"
 
 #if defined(OS_ANDROID)
diff --git a/gpu/ipc/service/BUILD.gn b/gpu/ipc/service/BUILD.gn
index 7f022f8..9ad2c9cd 100644
--- a/gpu/ipc/service/BUILD.gn
+++ b/gpu/ipc/service/BUILD.gn
@@ -46,10 +46,10 @@
   public_deps = [
     "//base",
     "//ipc",
-    "//ui/events:events_base",
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/gl",
+    "//ui/latency_info/ipc",
     "//url",
   ]
   deps = [
diff --git a/gpu/ipc/service/DEPS b/gpu/ipc/service/DEPS
index 0461b20..facf83e 100644
--- a/gpu/ipc/service/DEPS
+++ b/gpu/ipc/service/DEPS
@@ -2,6 +2,6 @@
   "+third_party/skia",
   "+ui/accelerated_widget_mac",
   "+ui/base",
-  "+ui/events",
+  "+ui/latency_info",
   "+ui/ozone",
 ]
diff --git a/gpu/ipc/service/gpu_channel_manager_delegate.h b/gpu/ipc/service/gpu_channel_manager_delegate.h
index 83f2dc11..803e011 100644
--- a/gpu/ipc/service/gpu_channel_manager_delegate.h
+++ b/gpu/ipc/service/gpu_channel_manager_delegate.h
@@ -10,8 +10,8 @@
 
 #if defined(OS_MACOSX)
 #include "ui/base/cocoa/remote_layer_api.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/mac/io_surface.h"
+#include "ui/latency_info/latency_info.h"
 #endif
 
 class GURL;
diff --git a/gpu/ipc/service/gpu_command_buffer_stub.h b/gpu/ipc/service/gpu_command_buffer_stub.h
index 9d17603..3b4992b 100644
--- a/gpu/ipc/service/gpu_command_buffer_stub.h
+++ b/gpu/ipc/service/gpu_command_buffer_stub.h
@@ -27,12 +27,12 @@
 #include "gpu/ipc/service/gpu_memory_manager.h"
 #include "ipc/ipc_listener.h"
 #include "ipc/ipc_sender.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 #include "ui/gfx/swap_result.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_preference.h"
+#include "ui/latency_info/latency_info.h"
 #include "url/gurl.h"
 
 namespace gpu {
diff --git a/gpu/ipc/service/image_transport_surface_overlay_mac.h b/gpu/ipc/service/image_transport_surface_overlay_mac.h
index e455cf00..a8c4600 100644
--- a/gpu/ipc/service/image_transport_surface_overlay_mac.h
+++ b/gpu/ipc/service/image_transport_surface_overlay_mac.h
@@ -13,9 +13,9 @@
 #include "gpu/ipc/service/gpu_command_buffer_stub.h"
 #include "gpu/ipc/service/image_transport_surface.h"
 #include "ui/base/cocoa/remote_layer_api.h"
-#include "ui/events/latency_info.h"
 #include "ui/gl/gl_surface.h"
 #include "ui/gl/gpu_switching_observer.h"
+#include "ui/latency_info/latency_info.h"
 
 @class CAContext;
 @class CALayer;
diff --git a/gpu/ipc/service/pass_through_image_transport_surface.h b/gpu/ipc/service/pass_through_image_transport_surface.h
index b63194a7..4c8f927 100644
--- a/gpu/ipc/service/pass_through_image_transport_surface.h
+++ b/gpu/ipc/service/pass_through_image_transport_surface.h
@@ -13,8 +13,8 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "gpu/ipc/service/image_transport_surface.h"
-#include "ui/events/latency_info.h"
 #include "ui/gl/gl_surface.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace gpu {
 class GpuChannelManager;
diff --git a/headless/README.md b/headless/README.md
index 0748cfd..be67643 100644
--- a/headless/README.md
+++ b/headless/README.md
@@ -5,6 +5,9 @@
 (e.g., the DOM) and generating bitmaps from page contents -- using all the
 modern web platform features provided by Chromium and Blink.
 
+See the [architecture design doc](https://docs.google.com/document/d/11zIkKkLBocofGgoTeeyibB2TZ_k7nR78v7kNelCatUE)
+for more information.
+
 ## Headless shell
 
 The headless shell is a sample application which demonstrates the use of the
diff --git a/ios/third_party/ochamcrest/BUILD.gn b/ios/third_party/ochamcrest/BUILD.gn
index 47f61359..4029427 100644
--- a/ios/third_party/ochamcrest/BUILD.gn
+++ b/ios/third_party/ochamcrest/BUILD.gn
@@ -2,20 +2,11 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-# OCHamcrest sources contains import rules using relative file names
-# ("HCAssertThat.h") and other using paths in an installed framework
-# (<OCHamcrest/HCMatcher.h>). In order to build, copy all the sources
-# to <(SHARED_INTERMEDIATE_DIR)/ios/third_party/ochmacrest/OCHamcrest
-# so that both type of import work (another option considered was to
-# build forwarding headers but this required duplicating the list of
-# files in GN build and was ruled out).
-#
-# To avoid ODR violation, direct import of ios/third_party/ochamcrest
-# is forbidden in ios/DEPS and code should instead use import as if
-# OCHamcrest was in a framework (i.e. #import <OCHamcrest/OCHamcrest.h>).
-copy("ochamcrest_copy_files") {
+import("//build/config/ios/rules.gni")
+
+ios_framework_bundle("ochamcrest") {
   testonly = true
-  visibility = [ ":ochamcrest" ]
+  output_name = "OCHamcrest"
   sources = [
     "src/Source/Core/HCAssertThat.h",
     "src/Source/Core/HCAssertThat.m",
@@ -170,27 +161,72 @@
     "src/Source/Library/Text/HCSubstringMatcher.m",
     "src/Source/OCHamcrest.h",
   ]
-  outputs = [
-    "$root_gen_dir/ios/third_party/ochamcrest/OCHamcrest/{{source_file_part}}",
+  public_headers = [
+    "src/Source/Core/HCAssertThat.h",
+    "src/Source/Core/HCBaseDescription.h",
+    "src/Source/Core/HCBaseMatcher.h",
+    "src/Source/Core/HCDescription.h",
+    "src/Source/Core/HCDiagnosingMatcher.h",
+    "src/Source/Core/HCMatcher.h",
+    "src/Source/Core/HCSelfDescribing.h",
+    "src/Source/Core/HCStringDescription.h",
+    "src/Source/Core/Helpers/HCCollect.h",
+    "src/Source/Core/Helpers/HCInvocationMatcher.h",
+    "src/Source/Core/Helpers/HCRequireNonNilObject.h",
+    "src/Source/Core/Helpers/HCWrapInMatcher.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailure.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporter.h",
+    "src/Source/Core/Helpers/TestFailureReporters/HCTestFailureReporterChain.h",
+    "src/Source/Library/Collection/HCEvery.h",
+    "src/Source/Library/Collection/HCHasCount.h",
+    "src/Source/Library/Collection/HCIsCollectionContaining.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInAnyOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionContainingInRelativeOrder.h",
+    "src/Source/Library/Collection/HCIsCollectionOnlyContaining.h",
+    "src/Source/Library/Collection/HCIsDictionaryContaining.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingEntries.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingKey.h",
+    "src/Source/Library/Collection/HCIsDictionaryContainingValue.h",
+    "src/Source/Library/Collection/HCIsEmptyCollection.h",
+    "src/Source/Library/Collection/HCIsIn.h",
+    "src/Source/Library/Decorator/HCDescribedAs.h",
+    "src/Source/Library/Decorator/HCIs.h",
+    "src/Source/Library/Logical/HCAllOf.h",
+    "src/Source/Library/Logical/HCAnyOf.h",
+    "src/Source/Library/Logical/HCIsAnything.h",
+    "src/Source/Library/Logical/HCIsNot.h",
+    "src/Source/Library/Number/HCIsCloseTo.h",
+    "src/Source/Library/Number/HCIsEqualToNumber.h",
+    "src/Source/Library/Number/HCIsTrueFalse.h",
+    "src/Source/Library/Number/HCNumberAssert.h",
+    "src/Source/Library/Number/HCOrderingComparison.h",
+    "src/Source/Library/Object/HCArgumentCaptor.h",
+    "src/Source/Library/Object/HCClassMatcher.h",
+    "src/Source/Library/Object/HCConformsToProtocol.h",
+    "src/Source/Library/Object/HCHasDescription.h",
+    "src/Source/Library/Object/HCHasProperty.h",
+    "src/Source/Library/Object/HCIsEqual.h",
+    "src/Source/Library/Object/HCIsInstanceOf.h",
+    "src/Source/Library/Object/HCIsNil.h",
+    "src/Source/Library/Object/HCIsSame.h",
+    "src/Source/Library/Object/HCIsTypeOf.h",
+    "src/Source/Library/Object/HCThrowsException.h",
+    "src/Source/Library/Text/HCIsEqualIgnoringCase.h",
+    "src/Source/Library/Text/HCIsEqualIgnoringWhiteSpace.h",
+    "src/Source/Library/Text/HCStringContains.h",
+    "src/Source/Library/Text/HCStringContainsInOrder.h",
+    "src/Source/Library/Text/HCStringEndsWith.h",
+    "src/Source/Library/Text/HCStringStartsWith.h",
+    "src/Source/Library/Text/HCSubstringMatcher.h",
+    "src/Source/OCHamcrest.h",
   ]
-}
 
-config("config") {
-  visibility = [ ":ochamcrest" ]
-  libs = [ "XCTest.framework" ]
-  include_dirs = [ "$root_gen_dir/ios/third_party/ochamcrest" ]
-}
+  libs = [
+    "Foundation.framework",
+    "UIKit.framework",
+  ]
 
-source_set("ochamcrest") {
-  testonly = true
-  configs += [
-    ":config",
-    "//build/config/compiler:enable_arc",
-    "//build/config/compiler:no_chromium_code",
-  ]
-  public_configs = [ ":config" ]
-  public_deps = [
-    ":ochamcrest_copy_files",
-  ]
-  sources = get_target_outputs(":ochamcrest_copy_files")
+  configs += [ "//build/config/compiler:enable_arc" ]
+  configs -= [ "//build/config/gcc:symbol_visibility_hidden" ]
 }
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 4015b72..0a5229a 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -339,8 +339,23 @@
   ]
 }
 
+bundle_data("ios_web_unittests_bundle_data") {
+  testonly = true
+  sources = [
+    "test/data/chrome.html",
+    "test/data/testbadpass.pkpass",
+    "test/data/testfavicon.png",
+    "test/data/testpass.pkpass",
+  ]
+  outputs = [
+    "{{bundle_resources_dir}}/{{source_root_relative_dir}}/" +
+        "{{source_file_part}}",
+  ]
+}
+
 test("ios_web_unittests") {
   deps = [
+    ":ios_web_unittests_bundle_data",
     ":test_support",
     ":web",
     "//base",
@@ -445,6 +460,7 @@
 
   sources = [
     "web_state/js/resources/plugin_placeholder.js",
+    "web_state/js/resources/post_request.js",
     "web_state/js/resources/window_id.js",
     "webui/resources/web_ui.js",
   ]
diff --git a/ios/web/web_state/ui/crw_web_controller+protected.h b/ios/web/web_state/ui/crw_web_controller+protected.h
index b1abfea..e6e163f 100644
--- a/ios/web/web_state/ui/crw_web_controller+protected.h
+++ b/ios/web/web_state/ui/crw_web_controller+protected.h
@@ -11,8 +11,11 @@
 
 #include <memory>
 
+#include "base/containers/mru_cache.h"
 #import "base/mac/objc_property_releaser.h"
 #include "base/mac/scoped_nsobject.h"
+#include "ios/web/net/cert_host_pair.h"
+#import "ios/web/net/crw_cert_verification_controller.h"
 #import "ios/web/public/navigation_manager.h"
 #include "ios/web/public/referrer.h"
 #include "ios/web/public/web_state/page_display_state.h"
@@ -49,6 +52,27 @@
 //   as the WKWebView will automatically retry the load.
 static NSString* const kWKWebViewErrorSourceKey = @"ErrorSource";
 typedef enum { NONE = 0, PROVISIONAL_LOAD, NAVIGATION } WKWebViewErrorSource;
+
+// Represents cert verification error, which happened inside
+// |webView:didReceiveAuthenticationChallenge:completionHandler:| and should
+// be checked inside |webView:didFailProvisionalNavigation:withError:|.
+struct CertVerificationError {
+  CertVerificationError(BOOL is_recoverable, net::CertStatus status)
+      : is_recoverable(is_recoverable), status(status) {}
+
+  BOOL is_recoverable;
+  net::CertStatus status;
+};
+
+// Type of Cache object for storing cert verification errors.
+typedef base::MRUCache<web::CertHostPair, CertVerificationError>
+    CertVerificationErrorsCacheType;
+
+// Maximum number of errors to store in cert verification errors cache.
+// Cache holds errors only for pending navigations, so the actual number of
+// stored errors is not expected to be high.
+static const CertVerificationErrorsCacheType::size_type kMaxCertErrorsCount =
+    100;
 }  // namespace
 
 // URL scheme for messages sent from javascript for asynchronous processing.
@@ -82,7 +106,8 @@
 
 // Category for methods used or implemented by implementation subclasses of
 // CRWWebController.
-@interface CRWWebController (ProtectedMethods)<WKUIDelegate>
+@interface CRWWebController (
+    ProtectedMethods)<WKUIDelegate, WKNavigationDelegate>
 
 #pragma mark Methods implemented by subclasses
 // Everything in this section must be implemented by subclasses.
@@ -97,13 +122,21 @@
 // The title of the page.
 @property(nonatomic, readonly) NSString* title;
 
-// A set of script managers whose scripts have been injected into the current
-// page.
-@property(nonatomic, readonly) NSMutableSet* injectedScriptManagers;
-
 // Downloader for PassKit files. Lazy initialized.
 @property(nonatomic, readonly) CRWPassKitDownloader* passKitDownloader;
 
+// The actual URL of the document object (i.e., the last committed URL).
+// TODO(crbug.com/549616): Remove this in favor of just updating the
+// navigation manager and treating that as authoritative. For now, this allows
+// sharing the flow that's currently in the superclass.
+@property(nonatomic, readonly) GURL documentURL;
+
+// YES if the user has interacted with the content area since the last URL
+// change.
+@property(nonatomic, readonly) BOOL interactionRegisteredSinceLastURLChange;
+
+- (CRWWebControllerPendingNavigationInfo*)pendingNavigationInfo;
+
 // Designated initializer.
 - (instancetype)initWithWebState:(std::unique_ptr<web::WebStateImpl>)webState;
 
@@ -113,6 +146,9 @@
 // Destroys the web view by setting webView property to nil.
 - (void)resetWebView;
 
+// Sets _documentURL to newURL, and updates any relevant state information.
+- (void)setDocumentURL:(const GURL&)newURL;
+
 // Returns the current URL of the web view, and sets |trustLevel| accordingly
 // based on the confidence in the verification.
 - (GURL)webURLWithTrustLevel:(web::URLVerificationTrustLevel*)trustLevel;
@@ -120,7 +156,7 @@
 // Returns the type of document object loaded in the web view.
 - (web::WebViewDocumentType)webViewDocumentType;
 
-//- (void)loadRequest:(NSMutableURLRequest*)request;
+- (void)loadRequest:(NSMutableURLRequest*)request;
 
 // Called before loading current URL in WebView.
 - (void)willLoadCurrentURLInWebView;
@@ -134,6 +170,9 @@
 // Cancels any load in progress in the web view.
 - (void)abortWebLoad;
 
+// Called when web view process has been terminated.
+- (void)webViewWebProcessDidCrash;
+
 // Sets zoom scale value for webview scroll view from |zoomState|.
 - (void)applyWebViewScrollZoomScaleFromZoomState:
     (const web::PageZoomState&)zoomState;
@@ -147,6 +186,28 @@
 // Convenience method to inform CWRWebDelegate about a blocked popup.
 - (void)didBlockPopupWithURL:(GURL)popupURL sourceURL:(GURL)sourceURL;
 
+// Called when a load ends in an SSL error and certificate chain.
+- (void)handleSSLCertError:(NSError*)error;
+
+// Updates SSL status for the current navigation item based on the information
+// provided by web view.
+- (void)updateSSLStatusForCurrentNavigationItem;
+
+// Used in webView:didReceiveAuthenticationChallenge:completionHandler: to reply
+// with NSURLSessionAuthChallengeDisposition and credentials.
+- (void)handleHTTPAuthForChallenge:(NSURLAuthenticationChallenge*)challenge
+                 completionHandler:
+                     (void (^)(NSURLSessionAuthChallengeDisposition,
+                               NSURLCredential*))completionHandler;
+
+// Used in webView:didReceiveAuthenticationChallenge:completionHandler: to
+// reply with NSURLSessionAuthChallengeDisposition and credentials.
+- (void)processAuthChallenge:(NSURLAuthenticationChallenge*)challenge
+         forCertAcceptPolicy:(web::CertAcceptPolicy)policy
+                  certStatus:(net::CertStatus)certStatus
+           completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
+                                       NSURLCredential*))completionHandler;
+
 #pragma mark - Optional methods for subclasses
 // Subclasses may overwrite methods in this section.
 
@@ -231,6 +292,9 @@
 // loaded.
 @property(nonatomic, readwrite) BOOL userInteractionRegistered;
 
+// YES if the web process backing _wkWebView is believed to currently be dead.
+@property(nonatomic, assign) BOOL webProcessIsDead;
+
 // Whether the web page is currently performing window.history.pushState or
 // window.history.replaceState
 @property(nonatomic, readonly) BOOL changingHistoryState;
@@ -244,6 +308,12 @@
 // Returns NavigationManager's session controller.
 @property(nonatomic, readonly) CRWSessionController* sessionController;
 
+// Controller used for certs verification to help with blocking requests with
+// bad SSL cert, presenting SSL interstitials and determining SSL status for
+// Navigation Items.
+@property(nonatomic, readonly)
+    CRWCertVerificationController* certVerificationController;
+
 // Returns a new script which wraps |script| with windowID check so |script| is
 // not evaluated on windowID mismatch.
 - (NSString*)scriptByAddingWindowIDCheckForScript:(NSString*)script;
@@ -301,6 +371,10 @@
 // if necssary. If they are already injected, this is a no-op.
 - (void)injectEarlyInjectionScripts;
 
+// Resets the set of script managers whose scripts have been injected into the
+// current page to an empty list.
+- (void)clearInjectedScriptManagers;
+
 // Inject windowID if not yet injected.
 - (void)injectWindowID;
 
@@ -333,6 +407,9 @@
                        targetFrame:(const web::FrameInfo*)targetFrame
                        isLinkClick:(BOOL)isLinkClick;
 
+// Registers load request with empty referrer and link or client redirect
+// transition based on user interaction state.
+- (void)registerLoadRequest:(const GURL&)URL;
 // Prepares web controller and delegates for anticipated page change.
 // Allows several methods to invoke webWill/DidAddPendingURL on anticipated page
 // change, using the same cached request and calculated transition types.
@@ -413,6 +490,10 @@
 // Returns the current entry from the underlying session controller.
 - (CRWSessionEntry*)currentSessionEntry;
 
+// Clears certVerification errors which happened inside
+// |webView:didReceiveAuthenticationChallenge:completionHandler:|.
+- (void)clearCertVerificationErrors;
+
 // Resets pending external request information.
 - (void)resetExternalRequest;
 
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm
index e69a1c7..621b4923 100644
--- a/ios/web/web_state/ui/crw_web_controller.mm
+++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -12,6 +12,7 @@
 #include <utility>
 
 #include "base/ios/block_types.h"
+#include "base/ios/ios_util.h"
 #import "base/ios/ns_error_util.h"
 #include "base/ios/weak_nsobject.h"
 #include "base/json/json_reader.h"
@@ -32,6 +33,7 @@
 #include "base/values.h"
 #include "components/prefs/pref_service.h"
 #include "components/url_formatter/url_formatter.h"
+#import "ios/net/http_response_headers_util.h"
 #import "ios/net/nsurlrequest_util.h"
 #include "ios/public/provider/web/web_ui_ios.h"
 #import "ios/web/crw_network_activity_indicator_manager.h"
@@ -42,6 +44,7 @@
 #import "ios/web/navigation/crw_session_entry.h"
 #import "ios/web/navigation/navigation_item_impl.h"
 #import "ios/web/navigation/navigation_manager_impl.h"
+#import "ios/web/net/crw_cert_verification_controller.h"
 #include "ios/web/net/request_group_util.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/favicon_url.h"
@@ -83,6 +86,7 @@
 #import "ios/web/web_state/web_controller_observer_bridge.h"
 #include "ios/web/web_state/web_state_facade_delegate.h"
 #import "ios/web/web_state/web_state_impl.h"
+#import "ios/web/web_state/wk_web_view_security_util.h"
 #import "ios/web/webui/crw_web_ui_manager.h"
 #import "net/base/mac/url_conversions.h"
 #include "net/base/net_errors.h"
@@ -175,6 +179,16 @@
   return static_cast<WKWebViewErrorSource>(
       [error.userInfo[kWKWebViewErrorSourceKey] integerValue]);
 }
+// Utility function for converting the WKWebViewErrorSource to the NSError
+// received by WKWebViews.
+NSError* WKWebViewErrorWithSource(NSError* error, WKWebViewErrorSource source) {
+  DCHECK(error);
+  base::scoped_nsobject<NSMutableDictionary> userInfo(
+      [error.userInfo mutableCopy]);
+  [userInfo setObject:@(source) forKey:kWKWebViewErrorSourceKey];
+  return
+      [NSError errorWithDomain:error.domain code:error.code userInfo:userInfo];
+}
 }  // namespace
 
 @interface CRWWebController () <CRWNativeContentDelegate,
@@ -275,6 +289,8 @@
   // Set to YES on window.history.willChangeState message. To NO on
   // window.history.didPushState or window.history.didReplaceState.
   BOOL _changingHistoryState;
+  // YES if the web process backing _wkWebView is believed to currently be dead.
+  BOOL _webProcessIsDead;
 
   std::unique_ptr<web::NewWindowInfo> _externalRequest;
 
@@ -288,6 +304,16 @@
   // Object that manages all early script injection into the web view.
   base::scoped_nsobject<CRWJSEarlyScriptManager> _earlyScriptManager;
 
+  // A set of script managers whose scripts have been injected into the current
+  // page.
+  // TODO(stuartmorgan): Revisit this approach; it's intended only as a stopgap
+  // measure to make all the existing script managers work. Longer term, there
+  // should probably be a couple of points where managers can register to have
+  // things happen automatically based on page lifecycle, and if they don't want
+  // to use one of those fixed points, they should make their scripts internally
+  // idempotent.
+  base::scoped_nsobject<NSMutableSet> _injectedScriptManagers;
+
   // Script manager for setting the windowID.
   base::scoped_nsobject<CRWJSWindowIdManager> _windowIDJSManager;
 
@@ -307,6 +333,14 @@
   base::scoped_nsobject<CRWWebControllerPendingNavigationInfo>
       _pendingNavigationInfo;
 
+  // The WKNavigation for the most recent load request.
+  base::scoped_nsobject<WKNavigation> _latestWKNavigation;
+
+  // The WKNavigation captured when |stopLoading| was called. Used for reporting
+  // WebController.EmptyNavigationManagerCausedByStopLoading UMA metric which
+  // helps with diagnosing a navigation related crash (crbug.com/565457).
+  base::WeakNSObject<WKNavigation> _stoppedWKNavigation;
+
   // CRWWebUIManager object for loading WebUI pages.
   base::scoped_nsobject<CRWWebUIManager> _webUIManager;
 }
@@ -448,6 +482,8 @@
 // Returns YES if the current navigation item corresponds to a web page
 // loaded by a POST request.
 - (BOOL)isCurrentNavigationItemPOST;
+// Returns whether the given navigation is triggered by a user link click.
+- (BOOL)isLinkNavigation:(WKNavigationType)navigationType;
 
 // Finds all the scrollviews in the view hierarchy and makes sure they do not
 // interfere with scroll to top when tapping the statusbar.
@@ -700,6 +736,14 @@
   _UIDelegate.reset(UIDelegate);
 }
 
+- (BOOL)webProcessIsDead {
+  return _webProcessIsDead;
+}
+
+- (void)setWebProcessIsDead:(BOOL)webProcessIsDead {
+  _webProcessIsDead = webProcessIsDead;
+}
+
 - (NSString*)scriptByAddingWindowIDCheckForScript:(NSString*)script {
   NSString* kTemplate = @"if (__gCrWeb['windowId'] === '%@') { %@; }";
   return [NSString stringWithFormat:kTemplate, [self windowId], script];
@@ -846,7 +890,7 @@
 }
 
 - (BOOL)isViewAlive {
-  return [self.containerView isViewAlive];
+  return !_webProcessIsDead && [self.containerView isViewAlive];
 }
 
 - (BOOL)contentIsHTML {
@@ -1129,6 +1173,17 @@
          type == WKNavigationTypeFormResubmitted;
 }
 
+- (BOOL)isLinkNavigation:(WKNavigationType)navigationType {
+  switch (navigationType) {
+    case WKNavigationTypeLinkActivated:
+      return YES;
+    case WKNavigationTypeOther:
+      return [self userClickedRecently];
+    default:
+      return NO;
+  }
+}
+
 - (void)injectEarlyInjectionScripts {
   DCHECK(self.webView);
   if (![_earlyScriptManager hasBeenInjected]) {
@@ -1140,6 +1195,10 @@
   [self injectWindowID];
 }
 
+- (void)clearInjectedScriptManagers {
+  _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
+}
+
 - (void)injectWindowID {
   if (![_windowIDJSManager hasBeenInjected]) {
     // Default value for shouldSuppressDialogs is NO, so updating them only
@@ -1281,8 +1340,43 @@
 }
 
 - (void)loadRequest:(NSMutableURLRequest*)request {
-  // Subclasses must implement this method.
-  NOTREACHED();
+  _latestWKNavigation.reset([[self.webView loadRequest:request] retain]);
+}
+
+- (void)registerLoadRequest:(const GURL&)URL {
+  // Get the navigation type from the last main frame load request, and try to
+  // map that to a PageTransition.
+  WKNavigationType navigationType =
+      self.pendingNavigationInfo ? [self.pendingNavigationInfo navigationType]
+                                 : WKNavigationTypeOther;
+  ui::PageTransition transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
+  switch (navigationType) {
+    case WKNavigationTypeLinkActivated:
+      transition = ui::PAGE_TRANSITION_LINK;
+      break;
+    case WKNavigationTypeFormSubmitted:
+    case WKNavigationTypeFormResubmitted:
+      transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
+      break;
+    case WKNavigationTypeBackForward:
+      transition = ui::PAGE_TRANSITION_FORWARD_BACK;
+      break;
+    case WKNavigationTypeReload:
+      transition = ui::PAGE_TRANSITION_RELOAD;
+      break;
+    case WKNavigationTypeOther:
+      // The "Other" type covers a variety of very different cases, which may
+      // or may not be the result of user actions. For now, guess based on
+      // whether there's been an interaction since the last URL change.
+      // TODO(crbug.com/549301): See if this heuristic can be improved.
+      transition = self.interactionRegisteredSinceLastURLChange
+                       ? ui::PAGE_TRANSITION_LINK
+                       : ui::PAGE_TRANSITION_CLIENT_REDIRECT;
+      break;
+  }
+  // The referrer is not known yet, and will be updated later.
+  const web::Referrer emptyReferrer;
+  [self registerLoadRequest:URL referrer:emptyReferrer transition:transition];
 }
 
 - (void)registerLoadRequest:(const GURL&)requestURL
@@ -2109,7 +2203,7 @@
 
 - (BOOL)scriptHasBeenInjectedForClass:(Class)JSInjectionManagerClass
                        presenceBeacon:(NSString*)beacon {
-  return [self.injectedScriptManagers containsObject:JSInjectionManagerClass];
+  return [_injectedScriptManagers containsObject:JSInjectionManagerClass];
 }
 
 - (void)injectScript:(NSString*)script forClass:(Class)JSInjectionManagerClass {
@@ -2129,7 +2223,7 @@
       script = [self scriptByAddingWindowIDCheckForScript:script];
     web::EvaluateJavaScript(self.webView, script, nil);
   }
-  [self.injectedScriptManagers addObject:JSInjectionManagerClass];
+  [_injectedScriptManagers addObject:JSInjectionManagerClass];
 }
 
 #pragma mark -
@@ -3948,6 +4042,8 @@
 }
 
 - (void)stopLoading {
+  _stoppedWKNavigation.reset(_latestWKNavigation);
+
   web::RecordAction(UserMetricsAction("Stop"));
   // Discard the pending and transient entried before notifying the tab model
   // observers of the change via |-abortLoad|.
@@ -3961,7 +4057,8 @@
   }
 }
 
-#pragma mark - WKUIDelegate Methods
+#pragma mark -
+#pragma mark WKUIDelegate Methods
 
 - (WKWebView*)webView:(WKWebView*)webView
     createWebViewWithConfiguration:(WKWebViewConfiguration*)configuration
@@ -4083,6 +4180,279 @@
 }
 
 #pragma mark -
+#pragma mark WKNavigationDelegate Methods
+
+- (void)webView:(WKWebView*)webView
+    decidePolicyForNavigationAction:(WKNavigationAction*)navigationAction
+                    decisionHandler:
+                        (void (^)(WKNavigationActionPolicy))decisionHandler {
+  _webProcessIsDead = NO;
+  if (self.isBeingDestroyed) {
+    decisionHandler(WKNavigationActionPolicyCancel);
+    return;
+  }
+
+  NSURLRequest* request = navigationAction.request;
+  GURL url = net::GURLWithNSURL(request.URL);
+
+  // The page will not be changed until this navigation is commited, so the
+  // retrieved state will be pending until |didCommitNavigation| callback.
+  [self updatePendingNavigationInfoFromNavigationAction:navigationAction];
+
+  web::FrameInfo targetFrame(navigationAction.targetFrame.mainFrame);
+  BOOL isLinkClick = [self isLinkNavigation:navigationAction.navigationType];
+  BOOL allowLoad = [self shouldAllowLoadWithRequest:request
+                                        targetFrame:&targetFrame
+                                        isLinkClick:isLinkClick];
+
+  if (allowLoad) {
+    allowLoad = self.webStateImpl->ShouldAllowRequest(request);
+    if (!allowLoad && navigationAction.targetFrame.mainFrame) {
+      [self.pendingNavigationInfo setCancelled:YES];
+    }
+  }
+
+  decisionHandler(allowLoad ? WKNavigationActionPolicyAllow
+                            : WKNavigationActionPolicyCancel);
+}
+
+- (void)webView:(WKWebView*)webView
+    decidePolicyForNavigationResponse:(WKNavigationResponse*)navigationResponse
+                      decisionHandler:
+                          (void (^)(WKNavigationResponsePolicy))handler {
+  if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
+    // Create HTTP headers from the response.
+    // TODO(crbug.com/546157): Due to the limited interface of
+    // NSHTTPURLResponse, some data in the HttpResponseHeaders generated here is
+    // inexact.  Once UIWebView is no longer supported, update WebState's
+    // implementation so that the Content-Language and the MIME type can be set
+    // without using this imperfect conversion.
+    scoped_refptr<net::HttpResponseHeaders> HTTPHeaders =
+        net::CreateHeadersFromNSHTTPURLResponse(
+            static_cast<NSHTTPURLResponse*>(navigationResponse.response));
+    self.webStateImpl->OnHttpResponseHeadersReceived(
+        HTTPHeaders.get(), net::GURLWithNSURL(navigationResponse.response.URL));
+  }
+
+  // The page will not be changed until this navigation is commited, so the
+  // retrieved state will be pending until |didCommitNavigation| callback.
+  [self updatePendingNavigationInfoFromNavigationResponse:navigationResponse];
+
+  BOOL allowNavigation = navigationResponse.canShowMIMEType;
+  if (allowNavigation) {
+    allowNavigation =
+        self.webStateImpl->ShouldAllowResponse(navigationResponse.response);
+    if (!allowNavigation && navigationResponse.isForMainFrame) {
+      [self.pendingNavigationInfo setCancelled:YES];
+    }
+  }
+  if ([self.passKitDownloader
+          isMIMETypePassKitType:[self.pendingNavigationInfo MIMEType]]) {
+    GURL URL = net::GURLWithNSURL(navigationResponse.response.URL);
+    [self.passKitDownloader downloadPassKitFileWithURL:URL];
+  }
+
+  handler(allowNavigation ? WKNavigationResponsePolicyAllow
+                          : WKNavigationResponsePolicyCancel);
+}
+
+// TODO(stuartmorgan): Move all the guesswork around these states out of the
+// superclass, and wire these up to the remaining methods.
+- (void)webView:(WKWebView*)webView
+    didStartProvisionalNavigation:(WKNavigation*)navigation {
+  GURL webViewURL = net::GURLWithNSURL(webView.URL);
+  if (webViewURL.is_empty() && base::ios::IsRunningOnIOS9OrLater()) {
+    // May happen on iOS9, however in didCommitNavigation: callback the URL
+    // will be "about:blank". TODO(eugenebut): File radar for this issue
+    // (crbug.com/523549).
+    webViewURL = GURL(url::kAboutBlankURL);
+  }
+
+  // Intercept renderer-initiated navigations. If this navigation has not yet
+  // been registered, do so. loadPhase check is necessary because
+  // lastRegisteredRequestURL may be the same as the webViewURL on a new tab
+  // created by window.open (default is about::blank).
+  if (self.lastRegisteredRequestURL != webViewURL ||
+      self.loadPhase != web::LOAD_REQUESTED) {
+    // Reset current WebUI if one exists.
+    [self clearWebUI];
+    // Restart app specific URL loads to properly capture state.
+    // TODO(crbug.com/546347): Extract necessary tasks for app specific URL
+    // navigation rather than restarting the load.
+    if (web::GetWebClient()->IsAppSpecificURL(webViewURL)) {
+      [self abortWebLoad];
+      NavigationManager::WebLoadParams params(webViewURL);
+      [self loadWithParams:params];
+      return;
+    } else {
+      [self registerLoadRequest:webViewURL];
+    }
+  }
+  // Ensure the URL is registered and loadPhase is as expected.
+  DCHECK(self.lastRegisteredRequestURL == webViewURL);
+  DCHECK(self.loadPhase == web::LOAD_REQUESTED);
+  _latestWKNavigation.reset([navigation retain]);
+}
+
+- (void)webView:(WKWebView*)webView
+    didReceiveServerRedirectForProvisionalNavigation:(WKNavigation*)navigation {
+  [self registerLoadRequest:net::GURLWithNSURL(webView.URL)
+                   referrer:[self currentReferrer]
+                 transition:ui::PAGE_TRANSITION_SERVER_REDIRECT];
+}
+
+- (void)webView:(WKWebView*)webView
+    didFailProvisionalNavigation:(WKNavigation*)navigation
+                       withError:(NSError*)error {
+  // Ignore provisional navigation failure if a new navigation has been started,
+  // for example, if a page is reloaded after the start of the provisional
+  // load but before the load has been committed.
+  if (![_latestWKNavigation isEqual:navigation]) {
+    return;
+  }
+
+  // TODO(crbug.com/570699): Remove this workaround once |stopLoading| does not
+  // discard pending navigation items.
+  if ((!self.webStateImpl ||
+       !self.webStateImpl->GetNavigationManagerImpl().GetVisibleItem()) &&
+      [error.domain isEqual:base::SysUTF8ToNSString(web::kWebKitErrorDomain)] &&
+      error.code == web::kWebKitErrorFrameLoadInterruptedByPolicyChange) {
+    // App is going to crash in this state (crbug.com/565457). Crash will occur
+    // on dereferencing visible navigation item, which is null. This scenario is
+    // possible after pending load was stopped for a child window. Early return
+    // to prevent the crash and report UMA metric to check if crash happening
+    // because the load was stopped.
+    UMA_HISTOGRAM_BOOLEAN(
+        "WebController.EmptyNavigationManagerCausedByStopLoading",
+        [_stoppedWKNavigation isEqual:navigation]);
+    return;
+  }
+
+  // Handle load cancellation for directly cancelled navigations without
+  // handling their potential errors. Otherwise, handle the error.
+  if ([self.pendingNavigationInfo cancelled]) {
+    [self loadCancelled];
+  } else {
+    error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
+
+    if (web::IsWKWebViewSSLCertError(error))
+      [self handleSSLCertError:error];
+    else
+      [self handleLoadError:error inMainFrame:YES];
+  }
+
+  // This must be reset at the end, since code above may need information about
+  // the pending load.
+  [self resetPendingNavigationInfo];
+  [self clearCertVerificationErrors];
+}
+
+- (void)webView:(WKWebView*)webView
+    didCommitNavigation:(WKNavigation*)navigation {
+  DCHECK_EQ(self.webView, webView);
+  [self clearCertVerificationErrors];
+  // This point should closely approximate the document object change, so reset
+  // the list of injected scripts to those that are automatically injected.
+  [self clearInjectedScriptManagers];
+  [self injectWindowID];
+
+  // This is the point where the document's URL has actually changed, and
+  // pending navigation information should be applied to state information.
+  [self setDocumentURL:net::GURLWithNSURL([self.webView URL])];
+  DCHECK(self.documentURL == self.lastRegisteredRequestURL);
+  self.webStateImpl->OnNavigationCommitted(self.documentURL);
+  [self commitPendingNavigationInfo];
+  if ([self currentBackForwardListItemHolder]->navigation_type() ==
+      WKNavigationTypeBackForward) {
+    // A fast back/forward won't call decidePolicyForNavigationResponse, so
+    // the MIME type needs to be updated explicitly.
+    NSString* storedMIMEType =
+        [self currentBackForwardListItemHolder]->mime_type();
+    if (storedMIMEType) {
+      self.webStateImpl->SetContentsMimeType(
+          base::SysNSStringToUTF8(storedMIMEType));
+    }
+  }
+  [self webPageChanged];
+
+  [self updateSSLStatusForCurrentNavigationItem];
+
+  // Report cases where SSL cert is missing for a secure connection.
+  if (self.documentURL.SchemeIsCryptographic()) {
+    scoped_refptr<net::X509Certificate> cert =
+        web::CreateCertFromChain([self.webView certificateChain]);
+    UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection",
+                          cert);
+  }
+}
+
+- (void)webView:(WKWebView*)webView
+    didFinishNavigation:(WKNavigation*)navigation {
+  DCHECK(!self.isHalted);
+  // Trigger JavaScript driven post-document-load-completion tasks.
+  // TODO(crbug.com/546350): Investigate using
+  // WKUserScriptInjectionTimeAtDocumentEnd to inject this material at the
+  // appropriate time rather than invoking here.
+  web::EvaluateJavaScript(webView, @"__gCrWeb.didFinishNavigation()", nil);
+  [self didFinishNavigation];
+}
+
+- (void)webView:(WKWebView*)webView
+    didFailNavigation:(WKNavigation*)navigation
+            withError:(NSError*)error {
+  [self handleLoadError:WKWebViewErrorWithSource(error, NAVIGATION)
+            inMainFrame:YES];
+  [self clearCertVerificationErrors];
+}
+
+- (void)webView:(WKWebView*)webView
+    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge
+                    completionHandler:
+                        (void (^)(NSURLSessionAuthChallengeDisposition,
+                                  NSURLCredential*))completionHandler {
+  NSString* authMethod = challenge.protectionSpace.authenticationMethod;
+  if ([authMethod isEqual:NSURLAuthenticationMethodHTTPBasic] ||
+      [authMethod isEqual:NSURLAuthenticationMethodNTLM] ||
+      [authMethod isEqual:NSURLAuthenticationMethodHTTPDigest]) {
+    [self handleHTTPAuthForChallenge:challenge
+                   completionHandler:completionHandler];
+    return;
+  }
+
+  if (![authMethod isEqual:NSURLAuthenticationMethodServerTrust]) {
+    completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
+    return;
+  }
+
+  SecTrustRef trust = challenge.protectionSpace.serverTrust;
+  base::ScopedCFTypeRef<SecTrustRef> scopedTrust(trust,
+                                                 base::scoped_policy::RETAIN);
+  base::WeakNSObject<CRWWebController> weakSelf(self);
+  [self.certVerificationController
+      decideLoadPolicyForTrust:scopedTrust
+                          host:challenge.protectionSpace.host
+             completionHandler:^(web::CertAcceptPolicy policy,
+                                 net::CertStatus status) {
+               base::scoped_nsobject<CRWWebController> strongSelf(
+                   [weakSelf retain]);
+               if (!strongSelf) {
+                 completionHandler(
+                     NSURLSessionAuthChallengeRejectProtectionSpace, nil);
+                 return;
+               }
+               [strongSelf processAuthChallenge:challenge
+                            forCertAcceptPolicy:policy
+                                     certStatus:status
+                              completionHandler:completionHandler];
+             }];
+}
+
+- (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView {
+  [self clearCertVerificationErrors];
+  [self webViewWebProcessDidCrash];
+}
+
+#pragma mark -
 #pragma mark Testing-Only Methods
 
 - (void)injectWebViewContentView:(id)webViewContentView {
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
index f6af880..5a11c53d 100644
--- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
+++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -8,8 +8,6 @@
 
 #include <utility>
 
-#include "base/containers/mru_cache.h"
-#include "base/ios/ios_util.h"
 #include "base/ios/weak_nsobject.h"
 #include "base/json/json_reader.h"
 #import "base/mac/scoped_nsobject.h"
@@ -17,13 +15,10 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/sys_string_conversions.h"
 #include "base/values.h"
-#import "ios/net/http_response_headers_util.h"
 #import "ios/web/navigation/crw_session_controller.h"
 #import "ios/web/navigation/crw_session_entry.h"
 #include "ios/web/navigation/navigation_item_impl.h"
-#include "ios/web/net/cert_host_pair.h"
 #import "ios/web/public/navigation_manager.h"
-#import "ios/web/net/crw_cert_verification_controller.h"
 #import "ios/web/net/crw_ssl_status_updater.h"
 #include "ios/web/public/browser_state.h"
 #include "ios/web/public/cert_store.h"
@@ -53,43 +48,6 @@
 #include "net/ssl/ssl_info.h"
 #include "url/url_constants.h"
 
-using web::NavigationManager;
-
-namespace {
-
-// Represents cert verification error, which happened inside
-// |webView:didReceiveAuthenticationChallenge:completionHandler:| and should
-// be checked inside |webView:didFailProvisionalNavigation:withError:|.
-struct CertVerificationError {
-  CertVerificationError(BOOL is_recoverable, net::CertStatus status)
-      : is_recoverable(is_recoverable), status(status) {}
-
-  BOOL is_recoverable;
-  net::CertStatus status;
-};
-
-// Type of Cache object for storing cert verification errors.
-typedef base::MRUCache<web::CertHostPair, CertVerificationError>
-    CertVerificationErrorsCacheType;
-
-// Maximum number of errors to store in cert verification errors cache.
-// Cache holds errors only for pending navigations, so the actual number of
-// stored errors is not expected to be high.
-const CertVerificationErrorsCacheType::size_type kMaxCertErrorsCount = 100;
-
-NSError* WKWebViewErrorWithSource(NSError* error, WKWebViewErrorSource source) {
-  DCHECK(error);
-  base::scoped_nsobject<NSMutableDictionary> userInfo(
-      [error.userInfo mutableCopy]);
-  [userInfo setObject:@(source) forKey:kWKWebViewErrorSourceKey];
-  return [NSError errorWithDomain:error.domain
-                             code:error.code
-                         userInfo:userInfo];
-}
-}  // namespace
-
-#pragma mark -
-
 @implementation CRWWebControllerPendingNavigationInfo
 @synthesize referrer = _referrer;
 @synthesize MIMEType = _MIMEType;
@@ -109,8 +67,7 @@
 #pragma mark -
 
 @interface CRWWKWebViewWebController ()<CRWSSLStatusUpdaterDataSource,
-                                        CRWSSLStatusUpdaterDelegate,
-                                        WKNavigationDelegate> {
+                                        CRWSSLStatusUpdaterDelegate> {
   // The WKWebView managed by this instance.
   base::scoped_nsobject<WKWebView> _wkWebView;
 
@@ -120,16 +77,6 @@
   // sharing the flow that's currently in the superclass.
   GURL _documentURL;
 
-  // A set of script managers whose scripts have been injected into the current
-  // page.
-  // TODO(stuartmorgan): Revisit this approach; it's intended only as a stopgap
-  // measure to make all the existing script managers work. Longer term, there
-  // should probably be a couple of points where managers can register to have
-  // things happen automatically based on page lifecycle, and if they don't want
-  // to use one of those fixed points, they should make their scripts internally
-  // idempotent.
-  base::scoped_nsobject<NSMutableSet> _injectedScriptManagers;
-
   // Object for loading POST requests with body.
   base::scoped_nsobject<CRWJSPOSTRequestLoader> _POSTRequestLoader;
 
@@ -152,17 +99,6 @@
   // YES if the user has interacted with the content area since the last URL
   // change.
   BOOL _interactionRegisteredSinceLastURLChange;
-
-  // YES if the web process backing _wkWebView is believed to currently be dead.
-  BOOL _webProcessIsDead;
-
-  // The WKNavigation for the most recent load request.
-  base::scoped_nsobject<WKNavigation> _latestWKNavigation;
-
-  // The WKNavigation captured when |stopLoading| was called. Used for reporting
-  // WebController.EmptyNavigationManagerCausedByStopLoading UMA metric which
-  // helps with diagnosing a navigation related crash (crbug.com/565457).
-  base::WeakNSObject<WKNavigation> _stoppedWKNavigation;
 }
 
 // Dictionary where keys are the names of WKWebView properties and values are
@@ -194,19 +130,10 @@
 // Sets the value of the webView property, and performs its basic setup.
 - (void)setWebView:(WKWebView*)webView;
 
-// Returns whether the given navigation is triggered by a user link click.
-- (BOOL)isLinkNavigation:(WKNavigationType)navigationType;
-
-// Sets _documentURL to newURL, and updates any relevant state information.
-- (void)setDocumentURL:(const GURL&)newURL;
-
 // Returns YES if the given WKBackForwardListItem is valid to use for
 // navigation.
 - (BOOL)isBackForwardListItemValid:(WKBackForwardListItem*)item;
 
-// Called when web view process has been terminated.
-- (void)webViewWebProcessDidCrash;
-
 // Asynchronously returns the referrer policy for the current page.
 - (void)queryPageReferrerPolicy:(void(^)(NSString*))responseHandler;
 
@@ -216,20 +143,6 @@
                    sourceURL:(GURL)sourceURL
               referrerPolicy:(const std::string&)referrerPolicyString;
 
-// Called when a load ends in an SSL error and certificate chain.
-- (void)handleSSLCertError:(NSError*)error;
-
-// Updates SSL status for the current navigation item based on the information
-// provided by web view.
-- (void)updateSSLStatusForCurrentNavigationItem;
-
-// Used in webView:didReceiveAuthenticationChallenge:completionHandler: to reply
-// with NSURLSessionAuthChallengeDisposition and credentials.
-- (void)handleHTTPAuthForChallenge:(NSURLAuthenticationChallenge*)challenge
-                 completionHandler:
-                     (void (^)(NSURLSessionAuthChallengeDisposition,
-                               NSURLCredential*))completionHandler;
-
 // Used in webView:didReceiveAuthenticationChallenge:completionHandler: to reply
 // with NSURLSessionAuthChallengeDisposition and credentials.
 + (void)processHTTPAuthForUser:(NSString*)user
@@ -237,18 +150,6 @@
              completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
                                          NSURLCredential*))completionHandler;
 
-// Used in webView:didReceiveAuthenticationChallenge:completionHandler: to
-// reply with NSURLSessionAuthChallengeDisposition and credentials.
-- (void)processAuthChallenge:(NSURLAuthenticationChallenge*)challenge
-         forCertAcceptPolicy:(web::CertAcceptPolicy)policy
-                  certStatus:(net::CertStatus)certStatus
-           completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition,
-                                       NSURLCredential*))completionHandler;
-
-// Registers load request with empty referrer and link or client redirect
-// transition based on user interaction state.
-- (void)registerLoadRequest:(const GURL&)url;
-
 // Returns YES if a KVO change to |newURL| could be a 'navigation' within the
 // document (hash change, pushState/replaceState, etc.). This should only be
 // used in the context of a URL KVO callback firing, and only if |isLoading| is
@@ -309,11 +210,6 @@
   [super close];
 }
 
-- (void)stopLoading {
-  _stoppedWKNavigation.reset(_latestWKNavigation);
-  [super stopLoading];
-}
-
 #pragma mark -
 #pragma mark Testing-Only Methods
 
@@ -328,10 +224,6 @@
   return _wkWebView.get();
 }
 
-- (NSMutableSet*)injectedScriptManagers {
-  return _injectedScriptManagers;
-}
-
 - (UIScrollView*)webScrollView {
   return [_wkWebView scrollView];
 }
@@ -340,6 +232,22 @@
   return [_wkWebView title];
 }
 
+- (GURL)documentURL {
+  return _documentURL;
+}
+
+- (BOOL)interactionRegisteredSinceLastURLChange {
+  return _interactionRegisteredSinceLastURLChange;
+}
+
+- (CRWCertVerificationController*)certVerificationController {
+  return _certVerificationController;
+}
+
+- (void)clearCertVerificationErrors {
+  _certVerificationErrors->Clear();
+}
+
 // Overridden to track interactions since URL change.
 - (void)setUserInteractionRegistered:(BOOL)flag {
   [super setUserInteractionRegistered:flag];
@@ -380,10 +288,6 @@
   return [self documentTypeFromMIMEType:base::SysUTF8ToNSString(MIMEType)];
 }
 
-- (void)loadRequest:(NSMutableURLRequest*)request {
-  _latestWKNavigation.reset([[_wkWebView loadRequest:request] retain]);
-}
-
 - (void)willLoadCurrentURLInWebView {
   // TODO(stuartmorgan): Get a WKWebView version of the request ID verification
   // code working for debug builds.
@@ -517,10 +421,6 @@
   [super handleLoadError:error inMainFrame:inMainFrame];
 }
 
-- (BOOL)isViewAlive {
-  return !_webProcessIsDead && [super isViewAlive];
-}
-
 #pragma mark Private methods
 
 - (NSDictionary*)wkWebViewObservers {
@@ -619,21 +519,10 @@
   for (NSString* keyPath in self.wkWebViewObservers) {
     [_wkWebView addObserver:self forKeyPath:keyPath options:0 context:nullptr];
   }
-  _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
+  [self clearInjectedScriptManagers];
   [self setDocumentURL:[self defaultURL]];
 }
 
-- (BOOL)isLinkNavigation:(WKNavigationType)navigationType {
-  switch (navigationType) {
-    case WKNavigationTypeLinkActivated:
-      return YES;
-    case WKNavigationTypeOther:
-      return [self userClickedRecently];
-    default:
-      return NO;
-  }
-}
-
 - (void)setDocumentURL:(const GURL&)newURL {
   if (newURL != _documentURL) {
     _documentURL = newURL;
@@ -651,7 +540,7 @@
 }
 
 - (void)webViewWebProcessDidCrash {
-  _webProcessIsDead = YES;
+  [self setWebProcessIsDead:YES];
 
   SEL cancelDialogsSelector = @selector(cancelDialogsForWebController:);
   if ([self.UIDelegate respondsToSelector:cancelDialogsSelector])
@@ -890,42 +779,6 @@
   completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
 }
 
-- (void)registerLoadRequest:(const GURL&)url {
-  // Get the navigation type from the last main frame load request, and try to
-  // map that to a PageTransition.
-  WKNavigationType navigationType =
-      self.pendingNavigationInfo ? [self.pendingNavigationInfo navigationType]
-                                 : WKNavigationTypeOther;
-  ui::PageTransition transition = ui::PAGE_TRANSITION_CLIENT_REDIRECT;
-  switch (navigationType) {
-    case WKNavigationTypeLinkActivated:
-      transition = ui::PAGE_TRANSITION_LINK;
-      break;
-    case WKNavigationTypeFormSubmitted:
-    case WKNavigationTypeFormResubmitted:
-      transition = ui::PAGE_TRANSITION_FORM_SUBMIT;
-      break;
-    case WKNavigationTypeBackForward:
-      transition = ui::PAGE_TRANSITION_FORWARD_BACK;
-      break;
-    case WKNavigationTypeReload:
-      transition = ui::PAGE_TRANSITION_RELOAD;
-      break;
-    case WKNavigationTypeOther:
-      // The "Other" type covers a variety of very different cases, which may
-      // or may not be the result of user actions. For now, guess based on
-      // whether there's been an interaction since the last URL change.
-      // TODO(crbug.com/549301): See if this heuristic can be improved.
-      transition = _interactionRegisteredSinceLastURLChange
-                       ? ui::PAGE_TRANSITION_LINK
-                       : ui::PAGE_TRANSITION_CLIENT_REDIRECT;
-      break;
-  }
-  // The referrer is not known yet, and will be updated later.
-  const web::Referrer emptyReferrer;
-  [self registerLoadRequest:url referrer:emptyReferrer transition:transition];
-}
-
 - (BOOL)isKVOChangePotentialSameDocumentNavigationToURL:(const GURL&)newURL {
   DCHECK([_wkWebView isLoading]);
   // If the origin changes, it can't be same-document.
@@ -1058,7 +911,7 @@
 - (void)webViewTitleDidChange {
   // WKWebView's title becomes empty when the web process dies; ignore that
   // update.
-  if (_webProcessIsDead) {
+  if (self.webProcessIsDead) {
     DCHECK_EQ(self.title.length, 0U);
     return;
   }
@@ -1169,279 +1022,4 @@
   }
 }
 
-#pragma mark -
-#pragma mark WKNavigationDelegate Methods
-
-- (void)webView:(WKWebView *)webView
-    decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction
-                    decisionHandler:
-        (void (^)(WKNavigationActionPolicy))decisionHandler {
-  _webProcessIsDead = NO;
-  if (self.isBeingDestroyed) {
-    decisionHandler(WKNavigationActionPolicyCancel);
-    return;
-  }
-
-  NSURLRequest* request = navigationAction.request;
-  GURL url = net::GURLWithNSURL(request.URL);
-
-  // The page will not be changed until this navigation is commited, so the
-  // retrieved state will be pending until |didCommitNavigation| callback.
-  [self updatePendingNavigationInfoFromNavigationAction:navigationAction];
-
-  web::FrameInfo targetFrame(navigationAction.targetFrame.mainFrame);
-  BOOL isLinkClick = [self isLinkNavigation:navigationAction.navigationType];
-  BOOL allowLoad = [self shouldAllowLoadWithRequest:request
-                                        targetFrame:&targetFrame
-                                        isLinkClick:isLinkClick];
-
-  if (allowLoad) {
-    allowLoad = self.webStateImpl->ShouldAllowRequest(request);
-    if (!allowLoad && navigationAction.targetFrame.mainFrame) {
-      [self.pendingNavigationInfo setCancelled:YES];
-    }
-  }
-
-  decisionHandler(allowLoad ? WKNavigationActionPolicyAllow
-                            : WKNavigationActionPolicyCancel);
-}
-
-- (void)webView:(WKWebView *)webView
-    decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse
-                      decisionHandler:
-                          (void (^)(WKNavigationResponsePolicy))handler {
-  if ([navigationResponse.response isKindOfClass:[NSHTTPURLResponse class]]) {
-    // Create HTTP headers from the response.
-    // TODO(crbug.com/546157): Due to the limited interface of
-    // NSHTTPURLResponse, some data in the HttpResponseHeaders generated here is
-    // inexact.  Once UIWebView is no longer supported, update WebState's
-    // implementation so that the Content-Language and the MIME type can be set
-    // without using this imperfect conversion.
-    scoped_refptr<net::HttpResponseHeaders> HTTPHeaders =
-        net::CreateHeadersFromNSHTTPURLResponse(
-            static_cast<NSHTTPURLResponse*>(navigationResponse.response));
-    self.webStateImpl->OnHttpResponseHeadersReceived(
-        HTTPHeaders.get(), net::GURLWithNSURL(navigationResponse.response.URL));
-  }
-
-  // The page will not be changed until this navigation is commited, so the
-  // retrieved state will be pending until |didCommitNavigation| callback.
-  [self updatePendingNavigationInfoFromNavigationResponse:navigationResponse];
-
-  BOOL allowNavigation = navigationResponse.canShowMIMEType;
-  if (allowNavigation) {
-    allowNavigation =
-        self.webStateImpl->ShouldAllowResponse(navigationResponse.response);
-    if (!allowNavigation && navigationResponse.isForMainFrame) {
-      [self.pendingNavigationInfo setCancelled:YES];
-    }
-  }
-  if ([self.passKitDownloader
-          isMIMETypePassKitType:[self.pendingNavigationInfo MIMEType]]) {
-    GURL URL = net::GURLWithNSURL(navigationResponse.response.URL);
-    [self.passKitDownloader downloadPassKitFileWithURL:URL];
-  }
-
-  handler(allowNavigation ? WKNavigationResponsePolicyAllow
-                          : WKNavigationResponsePolicyCancel);
-}
-
-// TODO(stuartmorgan): Move all the guesswork around these states out of the
-// superclass, and wire these up to the remaining methods.
-- (void)webView:(WKWebView *)webView
-    didStartProvisionalNavigation:(WKNavigation *)navigation {
-  GURL webViewURL = net::GURLWithNSURL(webView.URL);
-  if (webViewURL.is_empty() && base::ios::IsRunningOnIOS9OrLater()) {
-    // May happen on iOS9, however in didCommitNavigation: callback the URL
-    // will be "about:blank". TODO(eugenebut): File radar for this issue
-    // (crbug.com/523549).
-    webViewURL = GURL(url::kAboutBlankURL);
-  }
-
-  // Intercept renderer-initiated navigations. If this navigation has not yet
-  // been registered, do so. loadPhase check is necessary because
-  // lastRegisteredRequestURL may be the same as the webViewURL on a new tab
-  // created by window.open (default is about::blank).
-  if (self.lastRegisteredRequestURL != webViewURL ||
-      self.loadPhase != web::LOAD_REQUESTED) {
-    // Reset current WebUI if one exists.
-    [self clearWebUI];
-    // Restart app specific URL loads to properly capture state.
-    // TODO(crbug.com/546347): Extract necessary tasks for app specific URL
-    // navigation rather than restarting the load.
-    if (web::GetWebClient()->IsAppSpecificURL(webViewURL)) {
-      [self abortWebLoad];
-      NavigationManager::WebLoadParams params(webViewURL);
-      [self loadWithParams:params];
-      return;
-    } else {
-      [self registerLoadRequest:webViewURL];
-    }
-  }
-  // Ensure the URL is registered and loadPhase is as expected.
-  DCHECK(self.lastRegisteredRequestURL == webViewURL);
-  DCHECK(self.loadPhase == web::LOAD_REQUESTED);
-  _latestWKNavigation.reset([navigation retain]);
-}
-
-- (void)webView:(WKWebView *)webView
-    didReceiveServerRedirectForProvisionalNavigation:
-        (WKNavigation *)navigation {
-  [self registerLoadRequest:net::GURLWithNSURL(webView.URL)
-                   referrer:[self currentReferrer]
-                 transition:ui::PAGE_TRANSITION_SERVER_REDIRECT];
-}
-
-- (void)webView:(WKWebView *)webView
-    didFailProvisionalNavigation:(WKNavigation *)navigation
-                       withError:(NSError *)error {
-  // Ignore provisional navigation failure if a new navigation has been started,
-  // for example, if a page is reloaded after the start of the provisional
-  // load but before the load has been committed.
-  if (![_latestWKNavigation isEqual:navigation]) {
-    return;
-  }
-
-  // TODO(crbug.com/570699): Remove this workaround once |stopLoading| does not
-  // discard pending navigation items.
-  if ((!self.webStateImpl ||
-       !self.webStateImpl->GetNavigationManagerImpl().GetVisibleItem()) &&
-      [error.domain isEqual:base::SysUTF8ToNSString(web::kWebKitErrorDomain)] &&
-      error.code == web::kWebKitErrorFrameLoadInterruptedByPolicyChange) {
-    // App is going to crash in this state (crbug.com/565457). Crash will occur
-    // on dereferencing visible navigation item, which is null. This scenario is
-    // possible after pending load was stopped for a child window. Early return
-    // to prevent the crash and report UMA metric to check if crash happening
-    // because the load was stopped.
-    UMA_HISTOGRAM_BOOLEAN(
-        "WebController.EmptyNavigationManagerCausedByStopLoading",
-        [_stoppedWKNavigation isEqual:navigation]);
-    return;
-  }
-
-  // Handle load cancellation for directly cancelled navigations without
-  // handling their potential errors. Otherwise, handle the error.
-  if ([self.pendingNavigationInfo cancelled]) {
-    [self loadCancelled];
-  } else {
-    error = WKWebViewErrorWithSource(error, PROVISIONAL_LOAD);
-
-    if (web::IsWKWebViewSSLCertError(error))
-      [self handleSSLCertError:error];
-    else
-      [self handleLoadError:error inMainFrame:YES];
-  }
-
-  // This must be reset at the end, since code above may need information about
-  // the pending load.
-  [self resetPendingNavigationInfo];
-  _certVerificationErrors->Clear();
-}
-
-- (void)webView:(WKWebView *)webView
-    didCommitNavigation:(WKNavigation *)navigation {
-  DCHECK_EQ(_wkWebView, webView);
-  _certVerificationErrors->Clear();
-  // This point should closely approximate the document object change, so reset
-  // the list of injected scripts to those that are automatically injected.
-  _injectedScriptManagers.reset([[NSMutableSet alloc] init]);
-  [self injectWindowID];
-
-  // This is the point where the document's URL has actually changed, and
-  // pending navigation information should be applied to state information.
-  [self setDocumentURL:net::GURLWithNSURL([_wkWebView URL])];
-  DCHECK(_documentURL == self.lastRegisteredRequestURL);
-  self.webStateImpl->OnNavigationCommitted(_documentURL);
-  [self commitPendingNavigationInfo];
-  if ([self currentBackForwardListItemHolder]->navigation_type() ==
-      WKNavigationTypeBackForward) {
-    // A fast back/forward won't call decidePolicyForNavigationResponse, so
-    // the MIME type needs to be updated explicitly.
-    NSString* storedMIMEType =
-        [self currentBackForwardListItemHolder]->mime_type();
-    if (storedMIMEType) {
-      self.webStateImpl->SetContentsMimeType(
-          base::SysNSStringToUTF8(storedMIMEType));
-    }
-  }
-  [self webPageChanged];
-
-  [self updateSSLStatusForCurrentNavigationItem];
-
-  // Report cases where SSL cert is missing for a secure connection.
-  if (_documentURL.SchemeIsCryptographic()) {
-    scoped_refptr<net::X509Certificate> cert =
-        web::CreateCertFromChain([_wkWebView certificateChain]);
-    UMA_HISTOGRAM_BOOLEAN("WebController.WKWebViewHasCertForSecureConnection",
-                          cert);
-  }
-}
-
-- (void)webView:(WKWebView *)webView
-    didFinishNavigation:(WKNavigation *)navigation {
-  DCHECK(!self.isHalted);
-  // Trigger JavaScript driven post-document-load-completion tasks.
-  // TODO(crbug.com/546350): Investigate using
-  // WKUserScriptInjectionTimeAtDocumentEnd to inject this material at the
-  // appropriate time rather than invoking here.
-  web::EvaluateJavaScript(webView,
-                          @"__gCrWeb.didFinishNavigation()", nil);
-  [self didFinishNavigation];
-}
-
-- (void)webView:(WKWebView *)webView
-    didFailNavigation:(WKNavigation *)navigation
-            withError:(NSError *)error {
-  [self handleLoadError:WKWebViewErrorWithSource(error, NAVIGATION)
-            inMainFrame:YES];
-  _certVerificationErrors->Clear();
-}
-
-- (void)webView:(WKWebView*)webView
-    didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge*)challenge
-                    completionHandler:
-                        (void (^)(NSURLSessionAuthChallengeDisposition,
-                                  NSURLCredential*))completionHandler {
-  NSString* authMethod = challenge.protectionSpace.authenticationMethod;
-  if ([authMethod isEqual:NSURLAuthenticationMethodHTTPBasic] ||
-      [authMethod isEqual:NSURLAuthenticationMethodNTLM] ||
-      [authMethod isEqual:NSURLAuthenticationMethodHTTPDigest]) {
-    [self handleHTTPAuthForChallenge:challenge
-                   completionHandler:completionHandler];
-    return;
-  }
-
-  if (![authMethod isEqual:NSURLAuthenticationMethodServerTrust]) {
-    completionHandler(NSURLSessionAuthChallengeRejectProtectionSpace, nil);
-    return;
-  }
-
-  SecTrustRef trust = challenge.protectionSpace.serverTrust;
-  base::ScopedCFTypeRef<SecTrustRef> scopedTrust(trust,
-                                                 base::scoped_policy::RETAIN);
-  base::WeakNSObject<CRWWKWebViewWebController> weakSelf(self);
-  [_certVerificationController
-      decideLoadPolicyForTrust:scopedTrust
-                          host:challenge.protectionSpace.host
-             completionHandler:^(web::CertAcceptPolicy policy,
-                                 net::CertStatus status) {
-               base::scoped_nsobject<CRWWKWebViewWebController> strongSelf(
-                   [weakSelf retain]);
-               if (!strongSelf) {
-                 completionHandler(
-                     NSURLSessionAuthChallengeRejectProtectionSpace, nil);
-                 return;
-               }
-               [strongSelf processAuthChallenge:challenge
-                            forCertAcceptPolicy:policy
-                                     certStatus:status
-                              completionHandler:completionHandler];
-             }];
-}
-
-- (void)webViewWebContentProcessDidTerminate:(WKWebView*)webView {
-  _certVerificationErrors->Clear();
-  [self webViewWebProcessDidCrash];
-}
-
 @end
diff --git a/media/audio/mac/audio_low_latency_input_mac.cc b/media/audio/mac/audio_low_latency_input_mac.cc
index a8e90a8..1a6846a1 100644
--- a/media/audio/mac/audio_low_latency_input_mac.cc
+++ b/media/audio/mac/audio_low_latency_input_mac.cc
@@ -256,7 +256,6 @@
       buffer_size_was_changed_(false),
       audio_unit_render_has_worked_(false),
       device_listener_is_active_(false),
-      started_(false),
       last_sample_time_(0.0),
       last_number_of_frames_(0),
       total_lost_frames_(0),
@@ -551,29 +550,32 @@
   audio_unit_render_has_worked_ = false;
   StartAgc();
   OSStatus result = AudioOutputUnitStart(audio_unit_);
-  started_ = true;
-  if (started_) {
-    DCHECK(IsRunning()) << "Audio unit is started but not yet running";
-    // For UMA stat purposes, start a one-shot timer which detects when input
-    // callbacks starts indicating if input audio recording works as intended.
-    // CheckInputStartupSuccess() will check if |input_callback_is_active_| is
-    // true when the timer expires.
-    input_callback_timer_.reset(new base::OneShotTimer());
-    input_callback_timer_->Start(
-        FROM_HERE,
-        base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this,
-        &AUAudioInputStream::CheckInputStartupSuccess);
+  OSSTATUS_DLOG_IF(ERROR, result != noErr, result)
+      << "Failed to start acquiring data";
+  if (result != noErr) {
+    Stop();
+    return;
   }
+  DCHECK(IsRunning()) << "Audio unit started OK but is not yet running";
 
-  number_of_restart_indications_ = 0;
-  number_of_restart_attempts_ = 0;
+  // For UMA stat purposes, start a one-shot timer which detects when input
+  // callbacks starts indicating if input audio recording starts as intended.
+  // CheckInputStartupSuccess() will check if |input_callback_is_active_| is
+  // true when the timer expires.
+  input_callback_timer_.reset(new base::OneShotTimer());
+  input_callback_timer_->Start(
+      FROM_HERE,
+      base::TimeDelta::FromSeconds(kInputCallbackStartTimeoutInSeconds), this,
+      &AUAudioInputStream::CheckInputStartupSuccess);
+  DCHECK(input_callback_timer_->IsRunning());
+
+  // Also create and start a timer that provides periodic callbacks used to
+  // monitor if the input stream is alive or not.
   check_alive_timer_.reset(new base::RepeatingTimer());
   check_alive_timer_->Start(
       FROM_HERE, base::TimeDelta::FromSeconds(kCheckInputIsAliveTimeInSeconds),
       this, &AUAudioInputStream::CheckIfInputStreamIsAlive);
-
-  OSSTATUS_DLOG_IF(ERROR, !started_, result)
-      << "Failed to start acquiring data";
+  DCHECK(check_alive_timer_->IsRunning());
 }
 
 void AUAudioInputStream::Stop() {
@@ -584,7 +586,10 @@
     check_alive_timer_->Stop();
     check_alive_timer_.reset();
   }
-  input_callback_timer_.reset();
+  if (input_callback_timer_ != nullptr) {
+    input_callback_timer_->Stop();
+    input_callback_timer_.reset();
+  }
 
   if (audio_unit_ != nullptr) {
     // Stop the I/O audio unit.
@@ -605,7 +610,6 @@
 
   SetInputCallbackIsActive(false);
   ReportAndResetStats();
-  started_ = false;
   sink_ = nullptr;
   fifo_.Clear();
   io_buffer_frame_size_ = 0;
@@ -1233,6 +1237,13 @@
   if (!GetAutomaticGainControl())
     return;
 
+  // Clear this counter here when audio is active instead of in Start(),
+  // otherwise it would be cleared at each restart attempt and that would break
+  // the current design where only a certain number of restart attempts is
+  // allowed.
+  if (GetInputCallbackIsActive())
+    number_of_restart_attempts_ = 0;
+
   // Measure time since last callback. |last_callback_time_| is set the first
   // time in Start() and then updated in each data callback, hence if
   // |time_since_last_callback| is large (>1) and growing for each check, the
@@ -1267,10 +1278,11 @@
       GetInputCallbackIsActive() ? kNumberOfIndicationsToTriggerRestart : 0;
   if (number_of_restart_indications_ > restart_threshold &&
       number_of_restart_attempts_ < kMaxNumberOfRestartAttempts) {
-    RestartAudio();
+    SetInputCallbackIsActive(false);
     ++total_number_of_restart_attempts_;
     ++number_of_restart_attempts_;
     number_of_restart_indications_ = 0;
+    RestartAudio();
   }
 }
 
diff --git a/media/audio/mac/audio_low_latency_input_mac.h b/media/audio/mac/audio_low_latency_input_mac.h
index 7522b47..07b40a24 100644
--- a/media/audio/mac/audio_low_latency_input_mac.h
+++ b/media/audio/mac/audio_low_latency_input_mac.h
@@ -285,9 +285,6 @@
   // Only touched on the creating thread.
   bool device_listener_is_active_;
 
-  // Set to true when audio unit is running, or performing IO. False otherwise.
-  bool started_;
-
   // Stores the timestamp of the previous audio buffer provided by the OS.
   // We use this in combination with |last_number_of_frames_| to detect when
   // the OS has decided to skip providing frames (i.e. a glitch).
diff --git a/mojo/public/tools/manifest/manifest_collator.py b/mojo/public/tools/manifest/manifest_collator.py
index fa95e37..a2a3f2d 100755
--- a/mojo/public/tools/manifest/manifest_collator.py
+++ b/mojo/public/tools/manifest/manifest_collator.py
@@ -40,6 +40,14 @@
 def MergeBaseManifest(parent, base):
   MergeDicts(parent["capabilities"], base["capabilities"])
 
+  if "applications" in base:
+    if "applications" not in parent:
+      parent["applications"] = []
+    parent["applications"].extend(base["applications"])
+
+  if "process-group" in base:
+    parent["process-group"] = base["process-group"]
+
 
 def main():
   parser = argparse.ArgumentParser(
diff --git a/net/quic/test_tools/crypto_test_utils.cc b/net/quic/test_tools/crypto_test_utils.cc
index bae41af..67092d8 100644
--- a/net/quic/test_tools/crypto_test_utils.cc
+++ b/net/quic/test_tools/crypto_test_utils.cc
@@ -57,7 +57,7 @@
 // HexChar parses |c| as a hex character. If valid, it sets |*value| to the
 // value of the hex character and returns true. Otherwise it returns false.
 bool HexChar(char c, uint8_t* value) {
-  if (base::IsAsciiDigit(c)) {
+  if (c >= '0' && c <= '9') {
     *value = c - '0';
     return true;
   }
diff --git a/services/shell/shell.cc b/services/shell/shell.cc
index fac23f19..25db56b4 100644
--- a/services/shell/shell.cc
+++ b/services/shell/shell.cc
@@ -642,22 +642,21 @@
   instance_listeners_.AddPtr(std::move(listener));
 }
 
-void Shell::CreateShellClientWithFactory(const Identity& source,
-                                         const Identity& shell_client_factory,
+void Shell::CreateShellClientWithFactory(const Identity& shell_client_factory,
                                          const std::string& name,
                                          mojom::ShellClientRequest request) {
   mojom::ShellClientFactory* factory =
-      GetShellClientFactory(shell_client_factory, source);
+      GetShellClientFactory(shell_client_factory);
   factory->CreateShellClient(std::move(request), name);
 }
 
 mojom::ShellClientFactory* Shell::GetShellClientFactory(
-    const Identity& shell_client_factory_identity,
-    const Identity& source_identity) {
+    const Identity& shell_client_factory_identity) {
   auto it = shell_client_factories_.find(shell_client_factory_identity);
   if (it != shell_client_factories_.end())
     return it->second.get();
 
+  Identity source_identity(kShellName, mojom::kInheritUserID);
   mojom::ShellClientFactoryPtr factory;
   ConnectToInterface(this, source_identity, shell_client_factory_identity,
                      &factory);
@@ -745,7 +744,7 @@
         instance->StartWithClient(std::move(client));
         Identity factory(result->resolved_name, target.user_id(),
                          instance_name);
-        CreateShellClientWithFactory(source, factory, target.name(),
+        CreateShellClientWithFactory(factory, target.name(),
                                      std::move(request));
       } else {
         instance->StartWithFilePath(
diff --git a/services/shell/shell.gyp b/services/shell/shell.gyp
index 6cc23ba..778ebbe 100644
--- a/services/shell/shell.gyp
+++ b/services/shell/shell.gyp
@@ -111,7 +111,7 @@
     'dependencies': [
       'shell_lib',
       'shell_public',
-      'shell_test_interfaces',
+      'shell_test_public',
       '<(DEPTH)/base/base.gyp:base',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
       '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
@@ -121,8 +121,14 @@
       '<(DEPTH)/url/url.gyp:url_lib',
     ]
   }, {
-    'target_name': 'shell_test_interfaces',
+    'target_name': 'shell_test_public',
     'type': 'static_library',
+    'dependencies': [
+      'shell_test_interfaces',
+    ],
+  }, {
+    'target_name': 'shell_test_interfaces',
+    'type': 'none',
     'variables': {
       'mojom_files': [
         'tests/test.mojom',
diff --git a/services/shell/shell.h b/services/shell/shell.h
index 9151ebbb..85379b7 100644
--- a/services/shell/shell.h
+++ b/services/shell/shell.h
@@ -127,15 +127,13 @@
   // Called from the instance implementing mojom::Shell.
   void AddInstanceListener(mojom::InstanceListenerPtr listener);
 
-  void CreateShellClientWithFactory(const Identity& source,
-                                    const Identity& shell_client_factory,
+  void CreateShellClientWithFactory(const Identity& shell_client_factory,
                                     const std::string& name,
                                     mojom::ShellClientRequest request);
   // Returns a running ShellClientFactory for |shell_client_factory_identity|.
   // If there is not one running one is started for |source_identity|.
   mojom::ShellClientFactory* GetShellClientFactory(
-      const Identity& shell_client_factory_identity,
-      const Identity& source_identity);
+      const Identity& shell_client_factory_identity);
   void OnShellClientFactoryLost(const Identity& which);
 
   // Callback when remote Catalog resolves mojo:foo to mojo:bar.
diff --git a/services/shell/tests/connect/connect_test.mojom b/services/shell/tests/connect/connect_test.mojom
index c87f39a..949fe429 100644
--- a/services/shell/tests/connect/connect_test.mojom
+++ b/services/shell/tests/connect/connect_test.mojom
@@ -20,7 +20,7 @@
 interface StandaloneApp {
   // Attempts to connect to an application whose name is explicitly allowed by
   // the standalone app's CapabilitySpec, but whose enclosing package is not.
-  // The connection should be blocked and title should be "uninitialized".
+  // The connection should succeed anyway.
   ConnectToAllowedAppInBlockedPackage() => (string title);
 
   // Connects to mojo:connect_test_class_app & requests ClassInterface from it.
diff --git a/services/shell/tests/connect/connect_unittest.cc b/services/shell/tests/connect/connect_unittest.cc
index 7ea19b4..e94da0e5e 100644
--- a/services/shell/tests/connect/connect_unittest.cc
+++ b/services/shell/tests/connect/connect_unittest.cc
@@ -249,7 +249,8 @@
 // Ask the target application to attempt to connect to a third application
 // provided by a package whose id is permitted by the primary target's
 // CapabilityFilter but whose package is not. The connection should be
-// blocked and the returned title should be "uninitialized".
+// allowed regardless of the target's CapabilityFilter with respect to the
+// package.
 TEST_F(ConnectTest, BlockedPackage) {
   scoped_ptr<Connection> connection = connector()->Connect(kTestAppName);
   test::mojom::StandaloneAppPtr standalone_app;
@@ -259,7 +260,7 @@
   standalone_app->ConnectToAllowedAppInBlockedPackage(
       base::Bind(&ReceiveOneString, &title, &run_loop));
   run_loop.Run();
-  EXPECT_EQ("uninitialized", title);
+  EXPECT_EQ("A", title);
 }
 
 // BlockedInterface should not be exposed to this application because it is not
diff --git a/testing/variations/fieldtrial_testing_config_mac.json b/testing/variations/fieldtrial_testing_config_mac.json
index b1d0b83..a666b73 100644
--- a/testing/variations/fieldtrial_testing_config_mac.json
+++ b/testing/variations/fieldtrial_testing_config_mac.json
@@ -102,6 +102,11 @@
             "group_name": "Enabled"
         }
     ],
+    "OfferUploadCreditCards": [
+        {
+            "group_name": "Enabled"
+        }
+    ],
     "PageRevisitInstrumentation": [
         {
             "group_name": "Enabled"
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
index 7f6832c1..62898f4 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-browser-side-navigation
@@ -53,7 +53,7 @@
   http/tests/history/cross-origin-redirect-on-back.html [ Crash ]
   http/tests/history/post-replace-state-reload.html [ Crash Failure ]
   http/tests/navigation/location-reload-after-post.php [ Crash Failure ]
-  virtual/pointerevent/fast/events/before-unload-return-bad-value.html [ Crash Failure]
+  virtual/pointerevent/fast/events/before-unload-return-bad-value.html [ Crash Failure ]
   virtual/pointerevent/fast/events/before-unload-return-value-from-listener.html [ Crash Failure ]
   virtual/pointerevent/fast/events/before-unload-returnValue.html [ Crash Failure ]
   virtual/pointerevent/fast/events/drop-handler-should-not-stop-navigate.html [ Crash Failure ]
@@ -245,11 +245,11 @@
   fast/parser/empty-text-resource.html [ Crash Timeout ]
   fast/table/crash-splitColumn-2.html [ Crash Timeout ]
   fast/table/giantCellspacing.html [ Crash Timeout ]
-  fast/xmlhttprequest/null-document-xmlhttprequest-open.html [ Crash ]
+  fast/xmlhttprequest/null-document-xmlhttprequest-open.html [ Crash Timeout ]
   http/tests/loading/bad-server-subframe.html [ Crash Timeout ]
   http/tests/loading/pdf-commit-load-callbacks.html [ Crash ]
   http/tests/loading/redirect-methods.html [ Crash Failure ]
-  imported/web-platform-tests/html/browsers/browsing-the-web/history-traversal/popstate_event.html [ Crash Failure Crash Failure ]
+  imported/web-platform-tests/html/browsers/browsing-the-web/history-traversal/popstate_event.html [ Crash Failure Timeout ]
   imported/web-platform-tests/html/browsers/windows/browsing-context-names/browsing-context-default-name.html [ Crash Timeout ]
   imported/web-platform-tests/html/dom/dynamic-markup-insertion/opening-the-input-stream/004.html [ Crash Timeout ]
   imported/web-platform-tests/html/dom/dynamic-markup-insertion/opening-the-input-stream/005.html [ Crash Timeout ]
@@ -347,3 +347,9 @@
 
 # Regressions: Unexpected text-only failures (1)
   svg/filters/filter-refresh.svg [ Failure ]
+
+# Update on 16-4-13
+
+# Regressions: Unexpected text-only failures (3)
+  imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html [ Failure ]
+  imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 4749007..93290108 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1262,7 +1262,6 @@
 crbug.com/571721 inspector/console/console-xpath.html [ Timeout Pass ]
 
 crbug.com/580378 [ Mac ] fast/replaced/width100percent-searchfield.html [ Failure Pass ]
-crbug.com/571765 [ Linux Trusty Mac10.9 ] inspector/console/worker-eval-contains-stack.html [ Timeout Crash Pass ]
 
 crbug.com/551843 fast/text/fallback-traits-fixup.html [ NeedsManualRebaseline ]
 
@@ -1537,10 +1536,3 @@
 crbug.com/593679 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ NeedsManualRebaseline ]
 crbug.com/593679 virtual/scalefactor200/fast/hidpi/static/calendar-picker-appearance.html [ NeedsManualRebaseline ]
 crbug.com/593679 virtual/scalefactor200withzoom/fast/hidpi/static/calendar-picker-appearance.html [ NeedsManualRebaseline ]
-
-crbug.com/600248 imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html [ Crash ]
-crbug.com/600248 imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html [ Crash ]
-crbug.com/600248 imported/web-platform-tests/web-animations/animation-effect-timing/endDelay.html [ Failure ]
-crbug.com/600248 imported/web-platform-tests/web-animations/animation/constructor.html [ Failure Timeout ]
-crbug.com/600248 imported/web-platform-tests/web-animations/animation-node/idlharness.html [ Failure Timeout ]
-
diff --git a/third_party/WebKit/LayoutTests/W3CImportExpectations b/third_party/WebKit/LayoutTests/W3CImportExpectations
index 0a61e3d..d5c2b05 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -289,8 +289,7 @@
 ## Owners: jsbell@chromium.org
 # imported/web-platform-tests/user-timing [ Pass ]
 imported/web-platform-tests/vibration [ Skip ]
-## Owners: suzyh@chromium.org
-# imported/web-platform-tests/web-animations [ Pass ]
+imported/web-platform-tests/web-animations [ Skip ]
 imported/web-platform-tests/webaudio [ Skip ]
 imported/web-platform-tests/webdriver [ Skip ]
 imported/web-platform-tests/webgl [ Skip ]
@@ -320,7 +319,6 @@
 imported/web-platform-tests/webstorage/OWNERS [ Skip ]
 imported/web-platform-tests/mediacapture-streams/OWNERS [ Skip ]
 imported/web-platform-tests/touch-events/OWNERS [ Skip ]
-imported/web-platform-tests/web-animations/OWNERS [ Skip ]
 
 # Exceptions for individual files that fail due to bugs in the
 # upstream tests that we shouldn't bother importing until they are
diff --git a/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert-expected.txt b/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert-expected.txt
new file mode 100644
index 0000000..7a2add1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert-expected.txt
@@ -0,0 +1,2 @@
+PASS if this test didn't assert.
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert.html b/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert.html
new file mode 100644
index 0000000..6f53107
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/font-feature-settings-assert.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<style>
+    #x {
+        -webkit-font-feature-settings: "liga";
+        font-feature-settings: "liga";
+        transition: color 1s;
+    }
+</style>
+<div id="x">PASS if this test didn't assert.<div>
+<script>
+    if (window.testRunner) {
+        testRunner.dumpAsText();
+        testRunner.waitUntilDone();
+    }
+
+    x.offsetTop;
+    x.style.color = "green";
+
+    if (window.testRunner) {
+        requestAnimationFrame(() => {
+            testRunner.notifyDone();
+        });
+    }
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings-expected.txt b/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings-expected.txt
new file mode 100644
index 0000000..fd81a00
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings-expected.txt
@@ -0,0 +1,10 @@
+Local style change on element with font-feature-settings should not cause subtree recalc
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS internals.updateStyleAndReturnAffectedElementCount() is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings.html
new file mode 100644
index 0000000..ac6a665
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/font-feature-settings.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script src="../../../resources/js-test.js"></script>
+<style>
+    #x {
+        -webkit-font-feature-settings: "liga";
+        font-feature-settings: "liga"
+    }
+    .y {
+        background-color: green
+    }
+</style>
+<div id="x">
+    <div>
+        <div></div>
+        <div></div>
+        <div></div>
+        <div></div>
+    </div>
+</div>
+<script>
+    description("Local style change on element with font-feature-settings should not cause subtree recalc");
+
+    x.offsetTop;
+    x.className = "y";
+
+    if (window.internals)
+        shouldBe("internals.updateStyleAndReturnAffectedElementCount()", "1");
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky-expected.html
new file mode 100644
index 0000000..f2fe60d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky-expected.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        position: relative;
+        width: 250px;
+        height: 450px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 600px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .before {
+        background-color: orange;
+        height: 50px;
+    }
+
+    .after {
+        background-color: blue;
+        height: 50px;
+    }
+    .sticky {
+        background-color: green;
+        position: relative;
+        top: 250px;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: 0">
+        <div class="container">
+            <div class="before box"></div>
+            <div class="sticky box"></div>
+            <div class="after box"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky.html
new file mode 100644
index 0000000..2407ce92
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inflow-sticky.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 250px;
+        height: 450px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 600px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .before {
+        background-color: orange;
+        height: 50px;
+    }
+
+    .after {
+        background-color: blue;
+        height: 50px;
+    }
+    .sticky {
+        background-color: green;
+        position: sticky;
+        top: 300px;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group" style="top: 100px">
+        <div class="container">
+            <div class="before box"></div>
+            <div class="sticky box"></div>
+            <div class="after box"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child-expected.html
new file mode 100644
index 0000000..69d68570
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child-expected.html
@@ -0,0 +1,85 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+        font-family: 'Ahem';
+        font-size: 25px;
+        line-height: 2;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 220px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        width: 200px;
+        height: 200px;
+        color: blue;
+        position: relative;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        top: 50px;
+        left: 50px;
+        height: 50px;
+        width: 50px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 163px;">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 0">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 88px;">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 0;">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child.html
new file mode 100644
index 0000000..f8f64af
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-abspos-child.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+        font-family: 'Ahem';
+        font-size: 25px;
+        line-height: 2;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 220px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        width: 200px;
+        height: 200px;
+        color: blue;
+        position: sticky;
+        top: 100px;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        top: 50px;
+        left: 50px;
+        height: 50px;
+        width: 50px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 200px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>
+            <div class="child box"></div>
+            XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container-expected.html
new file mode 100644
index 0000000..4d3d80c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container-expected.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<style>
+body {
+    height: 2000px;
+    margin: 0;
+    overflow: hidden;
+    padding: 0;
+}
+.sticky {
+    width: 200px;
+    height: 200px;
+    background-color: green;
+    display: inline-block;
+    position: relative;
+    top: 200px;
+}
+.block {
+    width: 200px;
+    height: 200px;
+    background-color: red;
+}
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<span class="sticky"></span>
+<div class="block"></div>
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container.html
new file mode 100644
index 0000000..0006f479
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-anonymous-container.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+<style>
+body {
+    height: 2000px;
+    margin: 0;
+    overflow: hidden;
+    padding: 0;
+}
+.sticky {
+    width: 200px;
+    height: 200px;
+    background-color: green;
+    display: inline-block;
+    position: sticky;
+    top: 0;
+}
+.block {
+    width: 200px;
+    height: 200px;
+    background-color: red;
+}
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<span class="sticky"></span>
+<div class="block"></div>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-expected.html
new file mode 100644
index 0000000..9191dc26
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        font-family: 'Ahem';
+        font-size: 24px;
+        line-height: 2;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 220px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        width: 200px;
+        height: 200px;
+        color: blue;
+        position: relative;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        opacity: 0.8;
+        top: 50px;
+        left: 50px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 172px;">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 0">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 88px;">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky" style="top: 0;">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky.html b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky.html
new file mode 100644
index 0000000..114977c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/inline-sticky.html
@@ -0,0 +1,91 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+        font-family: 'Ahem';
+        font-size: 24px;
+        line-height: 2;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 220px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        width: 200px;
+        height: 200px;
+        color: blue;
+        position: sticky;
+        top: 100px;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        opacity: 0.8;
+        top: 50px;
+        left: 50px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+    <div class="group" style="top: 200px">
+        <div class="indicator box"></div>
+        <div class="container">
+            XXX <span class="sticky">XXXX</br>XXXX</br>XXXX</br>XXXX</br>XXXX</span> XXX
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash-expected.txt
new file mode 100644
index 0000000..8d039aa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash-expected.txt
@@ -0,0 +1,3 @@
+This test PASSES if it does not CRASH.
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash.html b/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash.html
new file mode 100644
index 0000000..0a474d77
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/overflow-layer-removed-crash.html
@@ -0,0 +1,34 @@
+<style>
+.scroll {
+    overflow: hidden;
+}
+
+.layer {
+    will-change: transform;
+}
+</style>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+function crash() {
+    document.getElementById('scroll').classList.remove('scroll');
+    document.getElementById('scroll').classList.remove('layer');
+    document.getElementById('layer').classList.remove('layer');
+    if (window.testRunner)
+        testRunner.notifyDone();
+}
+
+window.onload = function() {
+    // Call crash after 2 rafs.
+    requestAnimationFrame(requestAnimationFrame.bind(null, crash));
+}
+</script>
+<p>This test PASSES if it does not CRASH.</p>
+<div id="scroll" class="scroll layer">
+    <div class="layer">
+        <div id="layer" class="layer"></div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash-expected.txt
new file mode 100644
index 0000000..6fb47db4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash-expected.txt
@@ -0,0 +1,3 @@
+This test should not crash
+
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash.html b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash.html
new file mode 100644
index 0000000..b2c54b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-inline-sticky-crash.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+</style>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    
+    function doTest()
+    {
+        var stickyBox = document.getElementById('sticky');
+        stickyBox.parentNode.removeChild(stickyBox);
+        window.scrollTo(0, 10);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test should not crash</p>
+    <span id="sticky" class="sticky box"></span>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash-expected.txt b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash-expected.txt
new file mode 100644
index 0000000..7d8d089
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash-expected.txt
@@ -0,0 +1 @@
+This test should not crash
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash.html b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash.html
new file mode 100644
index 0000000..9510501
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/remove-sticky-crash.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+</style>
+<script>
+    if (window.testRunner)
+        testRunner.dumpAsText();
+    
+    function doTest()
+    {
+        var stickyBox = document.getElementById('sticky');
+        stickyBox.parentNode.removeChild(stickyBox);
+        window.scrollTo(0, 10);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test should not crash</p>
+    <div id="sticky" class="sticky box"></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky-expected.html
new file mode 100644
index 0000000..a51843a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky-expected.html
@@ -0,0 +1,59 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+    
+    .sticky {
+        background-color: silver;
+        position: relative;
+        top: 100px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            <img src="../resources/greenbox.png" class="sticky box" style="top: 200px;">
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box"></div>
+        <div class="container">
+            <img src="../resources/greenbox.png" class="sticky box" style="top: 100px;">
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky.html b/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky.html
new file mode 100644
index 0000000..17aedee1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/replaced-sticky.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+    
+    .sticky {
+        background-color: silver;
+        position: sticky;
+        top: 100px;
+    }
+    
+    .indicator {
+        display: none;
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box"></div>
+        <div class="container">
+            <img src="../resources/greenbox.png" class="sticky box">
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box"></div>
+        <div class="container">
+            <img src="../resources/greenbox.png" class="sticky box">
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container-expected.html
index 7fb00752..823cb4b6 100644
--- a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container-expected.html
@@ -1,27 +1,60 @@
 <!DOCTYPE html>
-<style type="text/css">
-div {
-    height: 100px;
-    width: 100px;
-}
-.spacer {
-    background-color: red;
-}
-.sticky {
-    background-color: green;
-    position: relative;
-}
-.absoffset {
-    background-color: green;
-    position: absolute;
-    top: -100px;
-}
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: relative;
+        top: 200px;
+        background-color: silver;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        top: 50px;
+        left: 50px;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
 </style>
-<div class="spacer"></div>
-<div class="sticky">
-    <!--
-    Tests that the absolute positioned child is positioned relative to the sticky container. You should see only a
-    green box as this will cover up the red box above the sticky div.
-    -->
-    <div class="absoffset"></div>
-</div>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box"></div>
+        <div class="container">
+            <div class="sticky box">
+                <div class="child box"></div>
+            </div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container.html
index e5fb6618..f3c47d23 100644
--- a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container.html
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-as-positioning-container.html
@@ -2,31 +2,73 @@
 <script>
 if (window.internals) {
     internals.settings.setCSSStickyPositionEnabled(true);
-}
+}           
 </script>
-<style type="text/css">
-div {
-    height: 100px;
-    width: 100px;
-}
-.spacer {
-    background-color: red;
-}
-.sticky {
-    background-color: green;
-    position: sticky;
-}
-.absoffset {
-    background-color: green;
-    position: absolute;
-    top: -100px;
-}
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: silver;
+    }
+    
+    .child {
+        position: absolute;
+        background-color: green;
+        top: 50px;
+        left: 50px;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 250px;
+        left: 50px;
+        background-color: red;
+    }
 </style>
-<div class="spacer"></div>
-<div class="sticky">
-    <!--
-    Tests that the absolute positioned child is positioned relative to the sticky container. You should see only a
-    green box as this will cover up the red box above the sticky div.
-    -->
-    <div class="absoffset"></div>
-</div>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box"></div>
+        <div class="container">
+            <div class="sticky box">
+                <div class="child box"></div>
+            </div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides-expected.html
new file mode 100644
index 0000000..94b0971a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides-expected.html
@@ -0,0 +1,61 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .container {
+        position: absolute;
+        width: 2000px;
+        height: 180px;
+        top: 50px;
+        outline: 2px solid black;
+    }
+
+    .vertical.container {
+        top: 0px;
+        left: 50px;
+        width: 180px;
+        height: 2000px;
+    }
+    
+    .box {
+        width: 800px;
+        height: 180px;
+    }
+    
+    .vertical .box {
+        width: 180px;
+        height: 500px;
+    }
+
+    .sticky {
+        position: relative;
+        left: 50px;
+        right: 50px;
+        background-color: green;
+    }
+    
+    .vertical .sticky {
+        left: 0;
+        top: 50px;
+        bottom: 50px;
+        background-color: blue;
+        opacity: 0.75;
+    }
+</style>
+</head>
+<body>
+    <div class="container">
+        <div class="sticky box"></div>
+    </div>
+    <div class="vertical container">
+        <div class="sticky box"></div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides.html
new file mode 100644
index 0000000..5ca5df9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-both-sides.html
@@ -0,0 +1,74 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .container {
+        position: absolute;
+        width: 2000px;
+        height: 180px;
+        top: 350px;
+        outline: 2px solid black;
+    }
+
+    .vertical.container {
+        top: 0px;
+        left: 350px;
+        width: 180px;
+        height: 2000px;
+    }
+    
+    .box {
+        width: 800px;
+        height: 180px;
+    }
+    
+    .vertical .box {
+        width: 180px;
+        height: 500px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 50px;
+        right: 50px;
+        background-color: green;
+    }
+    
+    .vertical .sticky {
+        left: 0;
+        top: 50px;
+        bottom: 50px;
+        background-color: blue;
+        opacity: 0.75;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(300, 300);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="container">
+        <div class="sticky box"></div>
+    </div>
+    <div class="vertical container">
+        <div class="sticky box"></div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding-expected.html
new file mode 100644
index 0000000..b9a0bab
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding-expected.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 400px;
+        overflow: hidden; /* Still scrollable with JS */
+        padding: 20px;
+        border: 1px solid black;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 300px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 150px;
+    }
+
+    .sticky {
+        position: relative;
+        bottom: 0px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollTop = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+        <div class="group" style="top: 350px">
+            <div class="indicator box" style="top: 0px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box" style="bottom: 150px;"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 250px">
+            <div class="indicator box" style="top: 100px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box" style="bottom: 50px;"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 200px">
+            <div class="indicator box" style="top: 150px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 500px;">
+    This test checks that sticky positioned blocks positioned correctly in overflow with padding.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding.html
new file mode 100644
index 0000000..5f61046
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-bottom-overflow-padding.html
@@ -0,0 +1,95 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 400px;
+        overflow: hidden; /* Still scrollable with JS */
+        padding: 20px;
+        border: 1px solid black;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 300px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 150px;
+    }
+
+    .sticky {
+        position: sticky;
+        bottom: 0px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollTop = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+        <div class="group" style="top: 350px">
+            <div class="indicator box" style="top: 0px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 250px">
+            <div class="indicator box" style="top: 100px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 200px">
+            <div class="indicator box" style="top: 150px;"></div>
+            <div class="container">
+                <div class="box"></div>
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 500px;">
+    This test checks that sticky positioned blocks positioned correctly in overflow with padding.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved-expected.html
new file mode 100644
index 0000000..38fd5c5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved-expected.html
@@ -0,0 +1,42 @@
+<!DOCTYPE html>
+<style>
+body {
+    margin: 0;
+    height: 2000px;
+    overflow: hidden; /* hide scrollbars */
+}
+
+#spacer {
+    height: 0px;
+}
+
+.container {
+    background-color: red;
+    width: 200px;
+    height: 400px;
+    outline: 2px solid black;
+}
+
+.box {
+    width: 200px;
+    height: 200px;
+}
+
+.sticky {
+    position: relative;
+    top: 200px;
+    background-color: green;
+}
+
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="spacer"></div>
+<div class="container">
+    <div class="sticky box"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved.html
new file mode 100644
index 0000000..b2bfc96
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-container-moved.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<style>
+body {
+    margin: 0;
+    height: 2000px;
+    overflow: hidden; /* hide scrollbars */
+}
+
+#spacer {
+    height: 200px;
+}
+
+.container {
+    background-color: red;
+    width: 200px;
+    height: 400px;
+    outline: 2px solid black;
+}
+
+.box {
+    width: 200px;
+    height: 200px;
+}
+
+.sticky {
+    position: sticky;
+    top: 0px;
+    background-color: green;
+}
+
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+    // When the spacer's height is changed the sticky container moves up which should now
+    // require sliding the sticky box down.
+    document.getElementById('spacer').style.height = '0px';
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="spacer"></div>
+<div class="container">
+    <div class="sticky box"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display-expected.html
new file mode 100644
index 0000000..25e7986
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display-expected.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+ 
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+ 
+    .container {
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+ 
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>Block</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <p>Table</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <p>Grid</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <p>Flex box</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+  <div style="position: absolute; top: 500px;">
+  This test checks the behavior of position:sticky with various display values.
+  There should be no red.
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display.html
new file mode 100644
index 0000000..773849b8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-display.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+ 
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+ 
+    .container {
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+ 
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>Block</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <p>Table</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="display: table"></div>
+        </div>
+    </div>
+
+    <p>Grid</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="display: grid"></div>
+        </div>
+    </div>
+
+    <p>Flex box</p>
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="display: flex"></div>
+        </div>
+    </div>
+  <div style="position: absolute; top: 500px;">
+  This test checks the behavior of position:sticky with various display values.
+  There should be no red.
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox-expected.html
new file mode 100644
index 0000000..d3024b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox-expected.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+ 
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+ 
+    .flex-container {
+        position: relative;
+        display: flex;
+        width: 200px;
+        height: 180px;
+        flex-flow: row wrap;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 100px;
+        height: 180px;
+    }
+
+    .flex-item {
+        width: 100px;
+        height: 180px;
+        display: flex;
+    }
+
+    .sticky {
+        position: relative;
+        background-color: green;
+    }
+
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test checks the behavior of position:sticky with flex box items.
+  There should be no red.</p>
+
+    <div class="group" style="left: 100px">
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item" style="left:100px"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 150px">
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item" style="left:50px"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox.html
new file mode 100644
index 0000000..18b11da3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-flexbox.html
@@ -0,0 +1,98 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+ 
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+ 
+    .flex-container {
+        position: relative;
+        display: flex;
+        width: 200px;
+        height: 180px;
+        flex-flow: row wrap;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 100px;
+        height: 180px;
+    }
+
+    .flex-item {
+        width: 100px;
+        height: 180px;
+        display: flex;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test checks the behavior of position:sticky with flex box items.
+  There should be no red.</p>
+
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 150px">
+        <div class="indicator box" style="left: 50px;"></div>
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="indicator box" style="left: 0;"></div>
+        <div class="flex-container" style="left: 0px;">
+            <div class="sticky flex-item"></div>
+            <div class="flex-item" style="background-color: green;"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid-expected.html
new file mode 100644
index 0000000..b713f1c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid-expected.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+
+    .grid-container {
+        display: grid;
+        grid-template-columns: 50% 50%;
+        grid-template-rows: 100%;
+        width: 200px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 100px;
+        height: 180px;
+    }
+
+    .grid-item {
+        width: 100%;
+        height: 100%;
+    }
+
+    .sticky {
+        left: 100px;
+        background-color: green;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test checks the behavior of position:sticky with grid items.
+  There should be no red.</p>
+
+    <div class="group" style="left: 100px">
+        <div class="grid-container" style="left: 100px">
+          <div class="sticky grid-item" style="grid-column: 2; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 1; grid-row: 1;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 150px">
+        <div class="grid-container" style="left: 100px; grid-template-columns: 25% 50% 25%">
+          <div class="sticky grid-item" style="grid-column: 2; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 3; grid-row: 1;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="grid-container" style="left: 100px">
+          <div class="sticky grid-item" style="grid-column: 1; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 2; grid-row: 1;"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid.html
new file mode 100644
index 0000000..527dabb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-grid.html
@@ -0,0 +1,97 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    p {
+        position: relative;
+        left: 100px;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+
+    .grid-container {
+        display: grid;
+        grid-template-columns: 50% 50%;
+        grid-template-rows: 100%;
+        width: 200px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+ 
+    .box {
+        width: 100px;
+        height: 180px;
+    }
+
+    .grid-item {
+        width: 100%;
+        height: 100%;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>This test checks the behavior of position:sticky with grid items.
+  There should be no red.</p>
+
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="grid-container">
+          <div class="sticky grid-item" style="grid-column: 1; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 2; grid-row: 1;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 150px">
+        <div class="indicator box" style="left: 50px;"></div>
+        <div class="grid-container" style="left: 100px">
+          <div class="sticky grid-item" style="grid-column: 1; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 2; grid-row: 1;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="indicator box" style="left: 0px;"></div>
+        <div class="grid-container" style="left: 100px">
+          <div class="sticky grid-item" style="grid-column: 1; grid-row: 1;"></div>
+          <div class="grid-item" style="grid-column: 2; grid-row: 1;"></div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr-expected.html
new file mode 100644
index 0000000..d7fb369
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    #overflow {
+        width: 600px;
+        height: 450px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 150px;
+    }
+
+    .container {
+        width: 400px;
+        height: 130px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 200px;
+        height: 130px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollLeft = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+This test checks that right offset is ignored with overconstrained sticky positioning and ltr text direction.
+There should be no red.
+    <div id="overflow">
+        <div class="group">
+            <div class="indicator box" style="left: 200px;"></div>
+            <div class="container">
+                <div class="sticky box" style="left: 200px;"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 100px">
+            <div class="indicator box" style="left: 100px;"></div>
+            <div class="container">
+                <div class="sticky box" style="left: 100px;"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 200px">
+            <div class="indicator box" style="left: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr.html
new file mode 100644
index 0000000..f4b55398
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-ltr.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    #overflow {
+        width: 600px;
+        height: 450px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 150px;
+    }
+
+    .container {
+        width: 400px;
+        height: 130px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 200px;
+        height: 130px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        right: 200px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollLeft = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+This test checks that right offset is ignored with overconstrained sticky positioning and ltr text direction.
+There should be no red.
+    <div id="overflow">
+        <div class="group">
+            <div class="indicator box" style="left: 200px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 100px">
+            <div class="indicator box" style="left: 100px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 200px">
+            <div class="indicator box" style="left: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl-expected.html
new file mode 100644
index 0000000..121d2d47
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl-expected.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    #overflow {
+        width: 600px;
+        height: 450px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 150px;
+    }
+
+    .container {
+        width: 400px;
+        height: 130px;
+        outline: 2px solid black;
+        direction: rtl;
+    }
+
+    .box {
+        width: 200px;
+        height: 130px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollLeft = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+This test checks that left offset is ignored with overconstrained sticky positioning and rtl text direction.
+There should be no red.
+    <div id="overflow">
+        <div class="group" style="left: 400px">
+            <div class="indicator box" style="left: 0;"></div>
+            <div class="container">
+                <div class="sticky box" style="left: 0"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 300px">
+            <div class="indicator box" style="left: 100px;"></div>
+            <div class="container">
+                <div class="sticky box" style="left: 100px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 200px">
+            <div class="indicator box" style="left: 200px;"></div>
+            <div class="container">
+                <div class="sticky box" style="left: 200px"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl.html
new file mode 100644
index 0000000..95f403d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-horizontally-overconstrained-rtl.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    #overflow {
+        width: 600px;
+        height: 450px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+
+    .group {
+        position: relative;
+        width: 500px;
+        height: 150px;
+    }
+
+    .container {
+        width: 400px;
+        height: 130px;
+        outline: 2px solid black;
+        direction: rtl;
+    }
+
+    .box {
+        width: 200px;
+        height: 130px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 600px;
+        right: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollLeft = 100;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+This test checks that left offset is ignored with overconstrained sticky positioning and rtl text direction.
+There should be no red.
+    <div id="overflow">
+        <div class="group" style="left: 400px">
+            <div class="indicator box" style="left: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 300px">
+            <div class="indicator box" style="left: 100px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="left: 200px">
+            <div class="indicator box" style="left: 200px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left-expected.html
new file mode 100644
index 0000000..35f1ee44f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left-expected.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+    
+    .container {
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        background-color: green;
+        position: absolute;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="left: -100px;">
+        <div class="indicator box" style="left: 200px;"></div>
+        <div class="container">
+            <div class="sticky box" style="left: 200px"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 0">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="left: 100px"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 0;"></div>
+        <div class="container">
+            <div class="sticky box" style="left: 0"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left.html
new file mode 100644
index 0000000..f515c04
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-left.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+    
+    .container {
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="left: 200px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 100px">
+        <div class="indicator box" style="left: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="indicator box" style="left: 0;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed-expected.html
new file mode 100644
index 0000000..e3086c0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed-expected.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<style>
+.scroller {
+    background-color: red;
+    border: 1px solid black;
+    width: 200px;
+    height: 200px;
+    margin-top: 10px;
+    outline: 2px solid black;
+    overflow: hidden; /* hide scrollbars */
+}
+
+.sticky {
+    background-color: green;
+    display: inline-block;
+    margin-top: 200px;
+    position: relative;
+    top: 0px;
+    width: 200px;
+    height: 200px;
+}
+
+</style>
+<script>
+function doTest()
+{
+    var stickyObjects = document.querySelectorAll('.sticky');
+    for (var i = 0; i < stickyObjects.length; i++) {
+        stickyObjects[i].style.marginTop = '0';
+    }
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div class="scroller">
+    <div class="sticky"></div>
+</div>
+<div class="scroller">
+    <div>
+        <div class="sticky"></div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed.html
new file mode 100644
index 0000000..e56b5b0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margin-changed.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<style>
+.scroller {
+    background-color: red;
+    border: 1px solid black;
+    width: 200px;
+    height: 200px;
+    margin-top: 10px;
+    outline: 2px solid black;
+    overflow: hidden; /* hide scrollbars */
+}
+
+.sticky {
+    background-color: green;
+    display: inline-block;
+    margin-top: 200px;
+    position: sticky;
+    top: 0px;
+    width: 200px;
+    height: 200px;
+}
+
+</style>
+<script>
+function doTest()
+{
+    var stickyObjects = document.querySelectorAll('.sticky');
+    for (var i = 0; i < stickyObjects.length; i++) {
+        stickyObjects[i].style.marginTop = '0';
+    }
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div class="scroller">
+    <div class="sticky"></div>
+</div>
+<div class="scroller">
+    <div>
+        <div class="sticky"></div>
+    </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins-expected.html
new file mode 100644
index 0000000..c5b876a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins-expected.html
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 180px;
+        height: 500px;
+    }
+    
+    .container {
+        position: relative;
+        width: 150px;
+        height: 400px;
+        border: 2px solid black;
+        padding: 5px;
+    }
+    
+    .box {
+        width: 120px;
+        height: 120px;
+    }
+
+    .sticky {
+        position: relative;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 37px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <!-- auto margins -->
+    <div class="group" style="top: -300px">
+        <div class="indicator box" style="top: 110px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: auto; top: 280px"></div>
+        </div>
+    </div>
+
+    <!-- px margins -->
+    <div class="group" style="top: -300px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: 20px; top: 240px"></div>
+        </div>
+    </div>
+
+    <!-- % margins -->
+    <div class="group" style="top: -300px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: 20%; top: 220px"></div>
+        </div>
+    </div>
+
+    <!-- % margins -->
+    <div class="group" style="top: -300px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container" style="width: 200px;">
+            <div class="sticky box" style="margin: 20%; top: 200px"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins.html
new file mode 100644
index 0000000..7c74c014
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-margins.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 180px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 150px;
+        height: 400px;
+        border: 2px solid black;
+        padding: 5px;
+    }
+    
+    .box {
+        width: 120px;
+        height: 120px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 10px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 37px;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 300);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <!-- auto margins -->
+    <div class="group">
+        <div class="indicator box" style="top: 110px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: auto;"></div>
+        </div>
+    </div>
+
+    <!-- px margins -->
+    <div class="group">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: 20px;"></div>
+        </div>
+    </div>
+
+    <!-- % margins -->
+    <div class="group">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box" style="margin: 20%;"></div>
+        </div>
+    </div>
+
+    <!-- % margins -->
+    <div class="group">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container" style="width: 200px;">
+            <div class="sticky box" style="margin: 20%;"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed-expected.html
new file mode 100644
index 0000000..a5ba103a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed-expected.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<style>
+body {
+    margin: 0;
+    height: 2000px;
+    overflow: hidden; /* hide scrollbars */
+}
+
+#container {
+    background-color: green;
+    width: 200px;
+    height: 400px;
+    outline: 2px solid black;
+    overflow: auto;
+}
+
+.box {
+    width: 200px;
+    height: 200px;
+}
+
+.sticky {
+    position: relative;
+    top: 0px;
+    background-color: red;
+}
+
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="container">
+    <div class="sticky box"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed.html
new file mode 100644
index 0000000..904af03
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflow-changed.html
@@ -0,0 +1,46 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<style>
+body {
+    margin: 0;
+    height: 2000px;
+    overflow: hidden; /* hide scrollbars */
+}
+
+#container {
+    background-color: green;
+    width: 200px;
+    height: 400px;
+    outline: 2px solid black;
+}
+
+.box {
+    width: 200px;
+    height: 200px;
+}
+
+.sticky {
+    position: sticky;
+    top: 0px;
+    background-color: red;
+}
+
+</style>
+<script>
+function doTest()
+{
+    window.scrollTo(0, 200);
+    // When the spacer's height is changed the sticky container moves up which should now
+    // require sliding the sticky box down.
+    document.getElementById('container').style.overflow = 'hidden';
+}
+window.addEventListener('load', doTest, false);
+</script>
+<div id="container">
+    <div class="sticky box"></div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing-expected.html
new file mode 100644
index 0000000..0b4c814e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing-expected.html
@@ -0,0 +1,64 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .container {
+        position: absolute;
+        width: 200px;
+        height: 400px;
+        margin: 10px;
+        left: 200px;
+        top: -300px;
+        outline: 2px solid black;
+    }
+    
+    .spacer {
+        height: 350px;
+        width: 20px;
+        background-color: black;
+    }
+    
+    .vertical .spacer {
+        height: 20px;
+        width: 350px;
+    }
+    
+    .vertical.container {
+        -webkit-writing-mode: vertical-rl;
+        top: 200px;
+        left: 700px;
+        width: 400px;
+        height: 200px;
+    }
+    
+    
+    .box {
+        width: 150px;
+        height: 150px;
+    }
+
+    .sticky {
+        position: relative;
+        background-color: green;
+        opacity: 0.75;
+    }
+</style>
+</head>
+<body>
+    <div class="container">
+        <div class="spacer"></div>
+        <div class="sticky box"></div>
+    </div>
+
+    <div class="vertical container">
+        <div class="spacer"></div>
+        <div class="sticky box"></div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing.html
new file mode 100644
index 0000000..62d0307c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-overflowing.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .container {
+        position: absolute;
+        width: 200px;
+        height: 400px;
+        margin: 10px;
+        left: 300px;
+        top: -200px;
+        font-family: Ahem;
+        font-size: 24px;
+        outline: 2px solid black;
+    }
+    
+    .vertical.container {
+        -webkit-writing-mode: vertical-rl;
+        top: 300px;
+        left: 800px;
+        width: 400px;
+        height: 200px;
+    }
+    
+    .spacer {
+        height: 350px;
+        width: 20px;
+        background-color: black;
+    }
+    
+    .vertical .spacer {
+        height: 20px;
+        width: 350px;
+    }
+
+    .box {
+        width: 150px;
+        height: 150px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 200px;
+        right: 200px;
+        background-color: green;
+        opacity: 0.75;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="container">
+        <div class="spacer"></div>
+        <div class="sticky box"></div>
+    </div>
+
+    <div class="vertical container">
+        <div class="spacer"></div>
+        <div class="sticky box"></div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main-expected.txt b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main-expected.txt
new file mode 100644
index 0000000..27297855
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main-expected.txt
@@ -0,0 +1,2 @@
+Has sticky position objects
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main.html
new file mode 100644
index 0000000..6b0e619
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-scrolls-on-main.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<pre id="mainThreadScrollingReasons"></pre>
+<div style="position: sticky"></div>
+<script>
+ if (window.testRunner)
+     testRunner.dumpAsText(true);
+ window.addEventListener('load', function() {
+     document.getElementById("mainThreadScrollingReasons").innerText = window.internals.mainThreadScrollingReasons(document);
+ });
+</script>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins-expected.html
new file mode 100644
index 0000000..f717910
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins-expected.html
@@ -0,0 +1,53 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+    
+    .container {
+        position: relative;
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="left: -100px">
+        <div class="container">
+            <div class="sticky box" style="right: 0;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: -100px">
+        <div class="container">
+            <div class="sticky box" style="right: 20px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: -100px">
+        <div class="container">
+            <div class="sticky box" style="right: 80px"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins.html
new file mode 100644
index 0000000..6463feb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-side-margins.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 200px;
+    }
+    
+    .container {
+        width: 400px;
+        height: 180px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        left: 100px;
+        background-color: green;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(300, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group" style="left: 200px">
+        <div class="container">
+            <div class="sticky box" style="margin: 0 auto;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="container">
+            <div class="sticky box" style="margin: 0 20px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="left: 200px">
+        <div class="container">
+            <div class="sticky box" style="margin: 0 20%;"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context-expected.html
index 46ea614..069e710 100644
--- a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context-expected.html
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context-expected.html
@@ -1,21 +1,47 @@
 <!DOCTYPE html>
-<style type="text/css">
-div {
-    height: 100px;
-    width: 100px;
-}
-.sticky {
-    background-color: green;
-    position: relative;
-}
-.red {
-    background-color: red;
-    margin-top: -100px;
-}
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+    }
+    
+    .child {
+        position: relative;
+        background-color: green;
+        z-index: 2;
+    }
 </style>
-<!--
-Tests that the sticky node will be popped out into a stacking context on top of the node which follows it. You should
-see no red boxes as the green sticky div should pop on top of the red div placed under it.
--->
-<div class="sticky"></div>
-<div class="red"></div>
+</head>
+<body>
+    <div class="group">
+        <div class="container">
+            <div class="sticky box">
+                <div class="child box"></div>
+            </div>
+        </div>
+    </div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context.html
index 46b159f0..cdaca834 100644
--- a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context.html
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-stacking-context.html
@@ -2,25 +2,58 @@
 <script>
 if (window.internals) {
     internals.settings.setCSSStickyPositionEnabled(true);
-}
+}           
 </script>
-<style type="text/css">
-div {
-    height: 100px;
-    width: 100px;
-}
-.sticky {
-    background-color: green;
-    position: sticky;
-}
-.red {
-    background-color: red;
-    margin-top: -100px;
-}
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+    }
+    
+    .intermediate {
+        position: absolute;
+        z-index: 1;
+        background-color: green
+    }
+    
+    .child {
+        position: relative;
+        background-color: red;
+        z-index: 2;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: blue;
+        z-index: 0;
+    }
 </style>
-<!--
-Tests that the sticky node will be popped out into a stacking context on top of the node which follows it. You should
-see no red boxes as the green sticky div should pop on top of the red div placed under it.
--->
-<div class="sticky"></div>
-<div class="red"></div>
+</head>
+<body>
+    <div class="indicator box"></div>
+    <div class="container">
+        <div class="intermediate box"></div>
+        <div class="sticky box">
+            <div class="child box"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash-expected.html
new file mode 100644
index 0000000..35c0ab8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash-expected.html
@@ -0,0 +1,9 @@
+<!DOCTYPE html>
+
+<html>
+<body>
+    <p>Test position: sticky for table column groups.</p>
+    <p>This test should not crash.</p>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash.html
new file mode 100644
index 0000000..608b335
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-col-crash.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<script>
+    function doTest()
+    {
+        crashBox.scrollIntoView(true);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <p>Test position: sticky for table column groups.</p>
+    <p>This test should not crash.</p>
+    <div id=crashBox style="display: table-column-group; position: sticky;"></div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top-expected.html
new file mode 100644
index 0000000..1350120c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top-expected.html
@@ -0,0 +1,68 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 200px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 100px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 0;"></div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 520px;">
+    This test checks that sticky positioned table rows are contained by their table.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top.html
new file mode 100644
index 0000000..56599022
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-row-top.html
@@ -0,0 +1,110 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+        border: hidden;
+        border-width: 0px;
+        border-spacing: 0px !important;
+        border-collapse:collapse;
+        cellspacing: 0;
+        cellpadding: 0;
+        padding: 0;
+    }
+
+    .box {
+        width: 200px;
+        height: 198px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="top: 200px;"></div>
+        <table class="container">
+            <tbody>
+                <tr class="sticky">
+                    <td class="box"></td>
+                </tr>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 100px;"></div>
+        <table class="container" style="">
+            <tbody>
+                <tr class="sticky">
+                    <td class="box"></td>
+                </tr>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div class="group" style="top: 200px">
+        <div class="indicator box" style="top: 0;"></div>
+        <table class="container" style="">
+            <tbody>
+                <tr class="sticky">
+                    <td class="box"></td>
+                </tr>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    <div style="position: absolute; top: 620px;">
+    This test checks that sticky positioned table rows are contained by their table.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top-expected.html
new file mode 100644
index 0000000..ccb6f91
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top-expected.html
@@ -0,0 +1,69 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 200px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 100px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 0;"></div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 520px;">
+    This test checks that sticky positioned table theads are contained by their table.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top.html
new file mode 100644
index 0000000..91e359d5
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-table-thead-top.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+        border: hidden;
+        border-width: 0px;
+        border-spacing: 0px !important;
+        border-collapse:collapse;
+        cellspacing: 0;
+        cellpadding: 0;
+        padding: 0;
+    }
+
+    .box {
+        width: 200px;
+        height: 198px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="top: 200px;"></div>
+        <table class="container">
+            <thead class="sticky">
+                <tr>
+                    <td class="box"></td>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 100px;"></div>
+        <table class="container" style="">
+            <thead class="sticky">
+                <tr>
+                    <td class="box"></td>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+
+    <div class="group" style="top: 200px">
+        <div class="indicator box" style="top: 0;"></div>
+        <table class="container" style="">
+            <thead class="sticky">
+                <tr>
+                    <td class="box"></td>
+                </tr>
+            </thead>
+            <tbody>
+                <tr>
+                    <td></td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+    <div style="position: absolute; top: 620px;">
+    This test checks that sticky positioned table theads are contained by their table.
+    There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-expected.html
new file mode 100644
index 0000000..eca9bcf
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-expected.html
@@ -0,0 +1,63 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 200px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 100px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 0;"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins-expected.html
new file mode 100644
index 0000000..b46bf7a
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins-expected.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        border: 12px solid black;
+        padding: 5px;
+    }
+    
+    .box {
+        width: 160px;
+        height: 160px;
+    }
+
+    .sticky {
+        position: relative;
+        margin: 20px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 37px;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box" style="top: 110px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 73px"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins.html
new file mode 100644
index 0000000..41030274
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-margins.html
@@ -0,0 +1,80 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        border: 12px solid black;
+        padding: 5px;
+    }
+    
+    .box {
+        width: 160px;
+        height: 160px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 10px;
+        margin: 20px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 37px;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="top: 110px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 200px">
+        <div class="indicator box" style="top: 37px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-expected.html
new file mode 100644
index 0000000..f87b967
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-expected.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden;
+        border: 1px solid black;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: relative;
+        top: 100px;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+This test checks that sticky positioned elements are contained by their enclosing ancestor with an overflow clip.
+There should be no red.
+    <div id="overflow">
+        <div class="spacer"></div>
+
+        <div class="group" style="top: -120px">
+            <div class="container">
+                <div class="sticky box" style="top: 200px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: -20px">
+            <div class="container">
+                <div class="sticky box" style="top: 120px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 120px">
+            <div class="container">
+                <div class="sticky box" style="top: 0"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment-expected.html
new file mode 100644
index 0000000..c013a76
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment-expected.html
@@ -0,0 +1,81 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden;
+        border: 1px solid black;
+        position: relative;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 500px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .hash {
+        width: 600px;
+        height: 10px;
+        background-color: gray;
+        position: absolute;
+        border: 0px;
+    }
+
+    .sticky {
+        position: relative;
+        top: 100px;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+
+        <div class="group" style="top: -120px">
+            <div class="container">
+                <div class="sticky box" style="top: 200px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: -20px">
+            <div class="container">
+                <div class="sticky box" style="top: 120px"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 120px">
+            <div class="container">
+                <div class="sticky box" style="top: 0"></div>
+            </div>
+        </div>
+        <div id="hash" class="hash" style="top: 0;">
+        </div>
+    </div>
+    <div style="position: absolute; top: 560px;">
+    This test checks that sticky positioning when scrolled by fragment.
+    There should be no red.
+    </div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment.html
new file mode 100644
index 0000000..a744216
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow-scroll-by-fragment.html
@@ -0,0 +1,109 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+<html>
+<head>
+<script>
+    function done()
+    {
+      if (window.testRunner)
+          window.testRunner.notifyDone();
+    }
+
+    if (window.location.hash == '') {
+        if (window.testRunner)
+            window.testRunner.waitUntilDone();
+        window.onhashchange = done;
+        location = '#hash';
+    }
+</script>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+        position: relative;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 500px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .hash {
+        width: 600px;
+        height: 10px;
+        background-color: gray;
+        position: absolute;
+        border: 0px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div id="overflow">
+        <div class="spacer"></div>
+        <div class="group">
+            <div class="indicator box" style="top: 200px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 100px">
+            <div class="indicator box" style="top: 120px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 240px">
+            <div class="indicator box" style="top: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+        <div id="hash" class="hash" style="top: 120px;">
+        </div>
+    </div>
+    <div style="position: absolute; top: 560px;">
+    This test checks that sticky positioning when scrolled by fragment.
+    There should be no red.
+    </div>
+</body>
+</html>
+
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow.html
new file mode 100644
index 0000000..6ad69c31
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top-overflow.html
@@ -0,0 +1,88 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+<html>
+<head>
+<style>
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 150px;
+        height: 500px;
+    }
+
+    #overflow {
+        width: 600px;
+        height: 550px;
+        overflow: hidden; /* Still scrollable with JS */
+        border: 1px solid black;
+    }
+
+    .spacer {
+        float: left;
+        width: 10px;
+        height: 1200px;
+    }
+    .container {
+        width: 100px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+
+    .box {
+        width: 100px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        document.getElementById('overflow').scrollTop = 120;
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+This test checks that sticky positioned elements are contained by their enclosing ancestor with an overflow clip.
+There should be no red.
+    <div id="overflow">
+        <div class="spacer"></div>
+        <div class="group">
+            <div class="indicator box" style="top: 200px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 100px">
+            <div class="indicator box" style="top: 120px;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+
+        <div class="group" style="top: 240px">
+            <div class="indicator box" style="top: 0;"></div>
+            <div class="container">
+                <div class="sticky box"></div>
+            </div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top.html
new file mode 100644
index 0000000..8523fd6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-top.html
@@ -0,0 +1,78 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 200px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained-expected.html
new file mode 100644
index 0000000..ad4a88bb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained-expected.html
@@ -0,0 +1,67 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="top: -100px;">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 200px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 0">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 100px;"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box" style="top: 0;"></div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 520px;">
+      This test checks that sticky positioned table theads are contained by their table.
+      There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained.html
new file mode 100644
index 0000000..a3bcf8d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-vertically-overconstrained.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        height: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        display: inline-block;
+        position: relative;
+        width: 250px;
+        height: 500px;
+    }
+    
+    .container {
+        width: 200px;
+        height: 400px;
+        outline: 2px solid black;
+    }
+    
+    .box {
+        width: 200px;
+        height: 200px;
+    }
+
+    .sticky {
+        position: sticky;
+        top: 100px;
+        bottom: 500px;
+        background-color: green;
+    }
+    
+    .indicator {
+        position: absolute;
+        top: 0;
+        left: 0;
+        background-color: red;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(0, 100);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group">
+        <div class="indicator box" style="top: 200px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 100px">
+        <div class="indicator box" style="top: 100px;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+
+    <div class="group" style="top: 200px">
+        <div class="indicator box" style="top: 0;"></div>
+        <div class="container">
+            <div class="sticky box"></div>
+        </div>
+    </div>
+    <div style="position: absolute; top: 620px;">
+        This test checks that sticky positioned table theads are contained by their table.
+        There should be no red.
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr-expected.html
new file mode 100644
index 0000000..7c172637
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr-expected.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 160px;
+    }
+    
+    .container {
+        -webkit-writing-mode: vertical-lr;
+        width: 300px;
+        height: 160px;
+        border: 2px solid black;
+        margin: 10px;
+        position: relative;
+    }
+    
+    .box {
+        width: 100px;
+        height: 100px;
+        margin: 5px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="left: -200px">
+        <div class="container">Before
+            <div class="box"></div> <!-- placeholder -->
+            <div class="sticky box" style="right: 0px;"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 300px">
+        <div class="container">Before
+            <div class="sticky box" style="position: relative;"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 700px">
+        <div class="container">Before
+            <div class="box"></div> <!-- placeholder -->
+            <div class="sticky box" style="left: 0px;"></div>After
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr.html
new file mode 100644
index 0000000..552d63b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-lr.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 160px;
+    }
+    
+    .container {
+        -webkit-writing-mode: vertical-lr;
+        width: 300px;
+        height: 160px;
+        border: 2px solid black;
+        margin: 10px;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        background-color: green;
+        width: 100px;
+        height: 100px;
+        left: 20px;
+        right: 20px;
+        margin: 5px;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group" style="left: -100px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 400px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 800px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl-expected.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl-expected.html
new file mode 100644
index 0000000..4cb1f9f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl-expected.html
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 160px;
+    }
+    
+    .container {
+        -webkit-writing-mode: vertical-rl;
+        width: 300px;
+        height: 160px;
+        border: 2px solid black;
+        margin: 10px;
+        position: relative;
+    }
+    
+    .box {
+        width: 100px;
+        height: 100px;
+        margin: 5px;
+    }
+
+    .sticky {
+        position: absolute;
+        background-color: green;
+    }
+</style>
+</head>
+<body>
+    <div class="group" style="left: -200px">
+        <div class="container">Before
+            <div class="box"></div> <!-- placeholder -->
+            <div class="sticky box" style="right: 0px;"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 300px">
+        <div class="container">Before
+            <div class="sticky box" style="position: relative;"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 700px">
+        <div class="container">Before
+            <div class="box"></div> <!-- placeholder -->
+            <div class="sticky box" style="left: 0px;"></div>After
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl.html b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl.html
new file mode 100644
index 0000000..63651fd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/sticky/sticky-writing-mode-vertical-rl.html
@@ -0,0 +1,73 @@
+<!DOCTYPE html>
+<script>
+if (window.internals) {
+    internals.settings.setCSSStickyPositionEnabled(true);
+}           
+</script>
+
+<html>
+<head>
+<style>
+    body {
+        margin: 0;
+        width: 2000px;
+        overflow: hidden; /* hide scrollbars */
+    }
+    
+    .group {
+        position: relative;
+        width: 500px;
+        height: 160px;
+    }
+    
+    .container {
+        -webkit-writing-mode: vertical-rl;
+        width: 300px;
+        height: 160px;
+        border: 2px solid black;
+        margin: 10px;
+    }
+    
+    .box {
+        width: 200px;
+        height: 180px;
+    }
+
+    .sticky {
+        position: sticky;
+        background-color: green;
+        width: 100px;
+        height: 100px;
+        left: 20px;
+        right: 20px;
+        margin: 5px;
+    }
+</style>
+<script>
+    function doTest()
+    {
+        window.scrollTo(100, 0);
+    }
+    window.addEventListener('load', doTest, false);
+</script>
+</head>
+<body>
+    <div class="group" style="left: -100px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 400px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+
+    <div class="group" style="left: 800px">
+        <div class="container">Before
+            <div class="sticky box"></div>After
+        </div>
+    </div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/mediastream/MediaDevices-getSupportedConstraints.html b/third_party/WebKit/LayoutTests/fast/mediastream/MediaDevices-getSupportedConstraints.html
new file mode 100644
index 0000000..b570a7e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/mediastream/MediaDevices-getSupportedConstraints.html
@@ -0,0 +1,27 @@
+<!DOCTYPE HTML>
+<title>mediaDevices.getSupportedConstraints</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+
+// Tests that getSupportedConstraints() returns what it should.
+test(function() {
+  supported_constraints = navigator.mediaDevices.getSupportedConstraints();
+  assert_true(supported_constraints.width);
+  assert_true(supported_constraints.height);
+  assert_true(supported_constraints.aspectRatio);
+  assert_true(supported_constraints.frameRate);
+  assert_true(supported_constraints.facingMode);
+  assert_true(supported_constraints.volume);
+  assert_true(supported_constraints.sampleRate);
+  assert_true(supported_constraints.sampleSize);
+  assert_true(supported_constraints.echoCancellation);
+  assert_true(supported_constraints.latency);
+  assert_true(supported_constraints.channelCount);
+  assert_true(supported_constraints.deviceId);
+  assert_true(supported_constraints.groupId);
+  // All non-supported values are "undefined".
+  assert_true(supported_constraints.nonsense === undefined);
+}, 'Supported constraints returns good data');
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/README.md b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/README.md
deleted file mode 100644
index 7afc875..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/README.md
+++ /dev/null
@@ -1,4 +0,0 @@
-Web Animations Tests
-====================
-
-Specification: http://w3c.github.io/web-animations/
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate-expected.txt
deleted file mode 100644
index d5b5f82c..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Element.animate() creates an Animation object 
-PASS Element.animate() creates an Animation object with a KeyframeEffect 
-FAIL Element.animate() accepts a property-indexed keyframe specification anim.effect.getFrames is not a function
-FAIL Element.animate() accepts a frame-indexed keyframe specification anim.effect.getFrames is not a function
-FAIL Element.animate() accepts a single-valued keyframe specification anim.effect.getFrames is not a function
-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 
-PASS Element.animate() correctly sets the id attribute when no id is specified 
-PASS Element.animate() correctly sets the id attribute 
-FAIL Element.animate() correctly sets the Animation's timeline assert_equals: expected (object) object "[object AnimationTimeline]" but got (undefined) undefined
-FAIL Element.animate() correctly sets the Animation's timeline when triggered on an element in a different document assert_equals: expected (object) object "[object AnimationTimeline]" but got (undefined) undefined
-PASS Element.animate() calls play on the Animation 
-FAIL CSSPseudoElement.animate() creates an Animation object document.getAnimations is not a function
-FAIL CSSPseudoElement.animate() creates an Animation object targeting to the correct CSSPseudoElement object document.getAnimations is not a function
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate.html
deleted file mode 100644
index afc9221..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate.html
+++ /dev/null
@@ -1,143 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Animatable.animate tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animatable-animate">
-<link rel="author" title="Brian Birtles" href="mailto:bbirtles@mozilla.com">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_class_string(anim, 'Animation', 'Returned object is an Animation');
-}, 'Element.animate() creates an Animation object');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_class_string(anim.effect, 'KeyframeEffect',
-                      'Returned Animation has a KeyframeEffect');
-}, 'Element.animate() creates an Animation object with a KeyframeEffect');
-
-// Animatable.animate() passes its |frames| argument to the KeyframeEffect
-// constructor. As a result, detailed tests of the handling of that argument
-// are found in the tests for that constructor. Here we just check that the
-// different types of arguments are correctly passed along.
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.effect.getFrames().length, 2);
-  assert_equals(anim.effect.getFrames()[0].opacity, '0');
-  assert_equals(anim.effect.getFrames()[1].opacity, '1');
-}, 'Element.animate() accepts a property-indexed keyframe specification');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate([ { opacity: 0 }, { opacity: 1 } ], 2000);
-  assert_equals(anim.effect.getFrames().length, 2);
-  assert_equals(anim.effect.getFrames()[0].opacity, '0');
-  assert_equals(anim.effect.getFrames()[1].opacity, '1');
-}, 'Element.animate() accepts a frame-indexed keyframe specification');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: 0 }, 2000);
-  assert_equals(anim.effect.getFrames().length, 1);
-  assert_equals(anim.effect.getFrames()[0].opacity, '0');
-}, 'Element.animate() accepts a single-valued keyframe specification');
-
-// As with the |frames| argument, Animatable.animate() passes its |options|
-// argument to the KeyframeEffect constructor as well. As a result, detailed
-// tests of the handling of that argument are found in the tests for that
-// constructor. Here we just check that the different types of arguments are
-// correctly passed along.
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.effect.timing.duration, 2000);
-  // Also check that unspecified parameters receive their default values
-  assert_equals(anim.effect.timing.fill, 'auto');
-}, 'Element.animate() accepts a double as an options argument');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { duration: Infinity, fill: 'forwards' });
-  assert_equals(anim.effect.timing.duration, Infinity);
-  assert_equals(anim.effect.timing.fill, 'forwards');
-  // Also check that unspecified parameters receive their default values
-  assert_equals(anim.effect.timing.direction, 'normal');
-}, 'Element.animate() accepts a KeyframeAnimationOptions argument');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] });
-  assert_equals(anim.effect.timing.duration, 'auto');
-}, 'Element.animate() accepts an absent options argument');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.id, '');
-}, 'Element.animate() correctly sets the id attribute when no id is specified');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, { id: 'test' });
-  assert_equals(anim.id, 'test');
-}, 'Element.animate() correctly sets the id attribute');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.timeline, document.timeline);
-}, 'Element.animate() correctly sets the Animation\'s timeline');
-
-async_test(function(t) {
-  var iframe = document.createElement('iframe');
-  iframe.src = 'data:text/html;charset=utf-8,';
-  iframe.width = 10;
-  iframe.height = 10;
-
-  iframe.addEventListener('load', t.step_func(function() {
-    var div = createDiv(t, iframe.contentDocument);
-    var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-    assert_equals(anim.timeline, iframe.contentDocument.timeline);
-    iframe.remove();
-    t.done();
-  }));
-
-  document.body.appendChild(iframe);
-}, 'Element.animate() correctly sets the Animation\'s timeline when ' +
-   'triggered on an element in a different document');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.playState, 'pending');
-}, 'Element.animate() calls play on the Animation');
-
-// Tests on CSSPseudoElement
-
-test(function(t) {
-  var pseudoTarget = createPseudo(t, 'before');
-  var anim = pseudoTarget.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_class_string(anim, 'Animation', 'The returned object is an Animation');
-}, 'CSSPseudoElement.animate() creates an Animation object');
-
-test(function(t) {
-  var pseudoTarget = createPseudo(t, 'before');
-  var anim = pseudoTarget.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_equals(anim.effect.target, pseudoTarget,
-                'The returned Animation targets to the correct object');
-}, 'CSSPseudoElement.animate() creates an Animation object targeting ' +
-   'to the correct CSSPseudoElement object');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration-expected.txt
deleted file mode 100644
index 3d369b24..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration-expected.txt
+++ /dev/null
@@ -1,35 +0,0 @@
-This is a testharness.js-based test.
-FAIL set duration 123.45 anim.effect.getComputedTiming is not a function
-FAIL set duration auto anim.effect.getComputedTiming is not a function
-FAIL set auto duration in animate as object anim.effect.getComputedTiming is not a function
-FAIL set duration Infinity anim.effect.getComputedTiming is not a function
-FAIL set negative duration in animate using a duration parameter assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, -1);..." did not throw
-PASS set negative Infinity duration in animate using a duration parameter 
-PASS set NaN duration in animate using a duration parameter 
-FAIL set negative duration in animate using an options object assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, { du..." did not throw
-FAIL set negative Infinity duration in animate using an options object assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, { du..." did not throw
-FAIL set NaN duration in animate using an options object assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, { du..." did not throw
-FAIL set abc string duration in animate using an options object assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, { du..." did not throw
-FAIL set 100 string duration in animate using an options object assert_throws: function "function () {
-    div.animate({ opacity: [ 0, 1 ] }, { du..." did not throw
-FAIL set negative duration assert_throws: function "function () {
-    anim.effect.timing.duration = -1;
-  }" did not throw
-FAIL set negative Infinity duration assert_throws: function "function () {
-    anim.effect.timing.duration = -Infinity..." did not throw
-FAIL set NaN duration assert_throws: function "function () {
-    anim.effect.timing.duration = NaN;
-  }" did not throw
-FAIL set duration abc assert_throws: function "function () {
-    anim.effect.timing.duration = 'abc';
-  }" did not throw
-FAIL set duration string 100 assert_throws: function "function () {
-    anim.effect.timing.duration = '100';
-  }" did not throw
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration.html
deleted file mode 100644
index 662ff40..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration.html
+++ /dev/null
@@ -1,149 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>duration tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationeffecttiming-duration">
-<link rel="author" title="Ryo Motozawa" href="mailto:motozawa@mozilla-japan.org">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.effect.timing.duration = 123.45;
-  assert_approx_equals(anim.effect.timing.duration, 123.45, 0.000001,
-                       'set duration 123.45');
-  assert_approx_equals(anim.effect.getComputedTiming().duration, 123.45,
-                       0.000001,
-                       'getComputedTiming() after set duration 123.45');
-}, 'set duration 123.45');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.effect.timing.duration = 'auto';
-  assert_equals(anim.effect.timing.duration, 'auto', 'set duration \'auto\'');
-  assert_equals(anim.effect.getComputedTiming().duration, 0,
-                'getComputedTiming() after set duration \'auto\'');
-}, 'set duration auto');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, { duration: 'auto' });
-  assert_equals(anim.effect.timing.duration, 'auto', 'set duration \'auto\'');
-  assert_equals(anim.effect.getComputedTiming().duration, 0,
-                'getComputedTiming() after set duration \'auto\'');
-}, 'set auto duration in animate as object');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.effect.timing.duration = Infinity;
-  assert_equals(anim.effect.timing.duration, Infinity, 'set duration Infinity');
-  assert_equals(anim.effect.getComputedTiming().duration, Infinity,
-                'getComputedTiming() after set duration Infinity');
-}, 'set duration Infinity');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, -1);
-  });
-}, 'set negative duration in animate using a duration parameter');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, -Infinity);
-  });
-}, 'set negative Infinity duration in animate using a duration parameter');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, NaN);
-  });
-}, 'set NaN duration in animate using a duration parameter');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, { duration: -1 });
-  });
-}, 'set negative duration in animate using an options object');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, { duration: -Infinity });
-  });
-}, 'set negative Infinity duration in animate using an options object');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, { duration: NaN });
-  });
-}, 'set NaN duration in animate using an options object');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, { duration: 'abc' });
-  });
-}, 'set abc string duration in animate using an options object');
-
-test(function(t) {
-  var div = createDiv(t);
-  assert_throws({ name: 'TypeError' }, function() {
-    div.animate({ opacity: [ 0, 1 ] }, { duration: '100' });
-  });
-}, 'set 100 string duration in animate using an options object');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({ name: 'TypeError' }, function() {
-    anim.effect.timing.duration = -1;
-  });
-}, 'set negative duration');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({ name: 'TypeError' }, function() {
-    anim.effect.timing.duration = -Infinity;
-  });
-}, 'set negative Infinity duration');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({ name: 'TypeError' }, function() {
-    anim.effect.timing.duration = NaN;
-  });
-}, 'set NaN duration');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({ name: 'TypeError' }, function() {
-    anim.effect.timing.duration = 'abc';
-  });
-}, 'set duration abc');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({ name: 'TypeError' }, function() {
-    anim.effect.timing.duration = '100';
-  });
-}, 'set duration string 100');
-
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/endDelay.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/endDelay.html
deleted file mode 100644
index c41bd697..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/endDelay.html
+++ /dev/null
@@ -1,98 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>endDelay tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationeffecttiming-enddelay">
-<link rel="author" title="Ryo Motozawa" href="mailto:motozawa@mozilla-japan.org">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.effect.timing.endDelay = 123.45;
-  assert_approx_equals(anim.effect.timing.endDelay, 123.45, 0.000001,
-                       'set endDelay 123.45');
-  assert_approx_equals(anim.effect.getComputedTiming().endDelay, 123.45,
-                       0.000001,
-                       'getComputedTiming() after set endDelay 123.45');
-}, 'set endDelay 123.45');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.effect.timing.endDelay = -1000;
-  assert_equals(anim.effect.timing.endDelay, -1000, 'set endDelay -1000');
-  assert_equals(anim.effect.getComputedTiming().endDelay, -1000,
-                'getComputedTiming() after set endDelay -1000');
-}, 'set endDelay -1000');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({name: "TypeError"}, function() {
-    anim.effect.timing.endDelay = Infinity;
-  }, 'we can not assign Infinity to timing.endDelay');
-}, 'set endDelay Infinity');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  assert_throws({name: "TypeError"}, function() {
-    anim.effect.timing.endDelay = -Infinity;
-  }, 'we can not assign negative Infinity to timing.endDelay');
-}, 'set endDelay negative Infinity');
-
-async_test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { duration: 100000, endDelay: 50000 });
-  anim.onfinish = t.step_func(function(event) {
-    assert_unreached('onfinish event should not be fired');
-  });
-
-  anim.ready.then(function() {
-    anim.currentTime = 100000;
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    t.done();
-  }));
-}, 'onfinish event is not fired duration endDelay');
-
-async_test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { duration: 100000, endDelay: 30000 });
-  var finishedTimelineTime;
-  anim.finished.then(function() {
-    finishedTimelineTime = anim.timeline.currentTime;
-  });
-
-  var receivedEvents = [];
-  anim.onfinish = function(event) {
-    receivedEvents.push(event);
-  }
-
-  anim.ready.then(function() {
-    anim.currentTime = 110000; // during endDelay
-    return waitForAnimationFrames(2);
-  }).then(t.step_func(function() {
-    assert_equals(receivedEvents.length, 0,
-      'onfinish event is should not be fired' +
-      'when currentTime is during endDelay');
-    anim.currentTime = 130000; // after endTime
-    return waitForAnimationFrames(2);
-  })).then(t.step_func_done(function() {
-    assert_equals(receivedEvents.length, 1, 'length of array should be one');
-    assert_equals(receivedEvents[0].timelineTime, finishedTimelineTime,
-      'receivedEvents[0].timelineTime should equal to the animation timeline '
-      + 'when finished promise is resolved');
-  }));
-}, 'onfinish event is fired currentTime is after endTime');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations-expected.txt
deleted file mode 100644
index c6b3964..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-This is a testharness.js-based test.
-PASS when duration is changed 
-FAIL when endDelay is changed assert_equals: set negative endDelay so as endTime is less than currentTime expected 0 but got 1
-FAIL when currentTime changed in duration:1000, delay: 500, endDelay: -500 assert_equals: set currentTime 1000 expected 0 but got 1
-FAIL when currentTime changed in duration:1000, delay: -500, endDelay: -500 assert_equals: when currentTime 0 expected 0 but got 1
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations.html
deleted file mode 100644
index fb47ae8..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations.html
+++ /dev/null
@@ -1,78 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Element.getAnimations tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#animationeffecttiming">
-<link rel="author" title="Ryo Motozawa" href="mailto:motozawa@mozilla-japan.org">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-  anim.finish();
-  assert_equals(div.getAnimations().length, 0, 'animation finished');
-  anim.effect.timing.duration += 100000;
-  assert_equals(div.getAnimations()[0], anim, 'set duration 102000');
-  anim.effect.timing.duration = 0;
-  assert_equals(div.getAnimations().length, 0, 'set duration 0');
-  anim.effect.timing.duration = 'auto';
-  assert_equals(div.getAnimations().length, 0, 'set duration \'auto\'');
-}, 'when duration is changed');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 2000);
-
-  anim.effect.timing.endDelay = -3000;
-  assert_equals(div.getAnimations().length, 0,
-    'set negative endDelay so as endTime is less than currentTime');
-  anim.effect.timing.endDelay = 1000;
-  assert_equals(div.getAnimations()[0], anim,
-    'set positive endDelay so as endTime is more than currentTime');
-
-  anim.effect.timing.duration = 1000;
-  anim.currentTime = 1500;
-  assert_equals(div.getAnimations().length, 0,
-    'set currentTime less than endTime');
-  anim.effect.timing.endDelay = -500;
-  anim.currentTime = 400;
-  assert_equals(div.getAnimations()[0], anim,
-    'set currentTime less than endTime when endDelay is negative value');
-  anim.currentTime = 500;
-  assert_equals(div.getAnimations().length, 0,
-    'set currentTime same as endTime when endDelay is negative value');
-  anim.currentTime = 1000;
-  assert_equals(div.getAnimations().length, 0,
-    'set currentTime same as duration when endDelay is negative value');
-}, 'when endDelay is changed');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { duration: 1000, delay: 500, endDelay: -500 });
-  assert_equals(div.getAnimations()[0], anim, 'when currentTime 0');
-  anim.currentTime = 500;
-  assert_equals(div.getAnimations()[0], anim, 'set currentTime 500');
-  anim.currentTime = 1000;
-  assert_equals(div.getAnimations().length, 0, 'set currentTime 1000');
-}, 'when currentTime changed in duration:1000, delay: 500, endDelay: -500');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { duration: 1000, delay: -500, endDelay: -500 });
-  assert_equals(div.getAnimations().length, 0, 'when currentTime 0');
-  anim.currentTime = 500;
-  assert_equals(div.getAnimations().length, 0, 'set currentTime 500');
-  anim.currentTime = 1000;
-  assert_equals(div.getAnimations().length, 0, 'set currentTime 1000');
-}, 'when currentTime changed in duration:1000, delay: -500, endDelay: -500');
-
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle-expected.txt
deleted file mode 100644
index 58d9dff6..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-PASS changed duration immediately updates its computed styles 
-PASS change currentTime when fill is none and endDelay is positive 
-PASS change currentTime when fill forwards and endDelay is positive 
-PASS change currentTime when fill none and endDelay is negative 
-FAIL change currentTime when fill forwards and endDelay is negative assert_equals: set currentTime same as endTime expected "0" but got "0.5"
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle.html
deleted file mode 100644
index 278392c..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle.html
+++ /dev/null
@@ -1,107 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>getComputedStyle tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#animationeffecttiming">
-<link rel="author" title="Ryo Motozawa" href="mailto:motozawa@mozilla-japan.org">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 100000);
-  anim.finish();
-  assert_equals(getComputedStyle(div).opacity, '1', 'animation finished');
-  anim.effect.timing.duration *= 2;
-  assert_equals(getComputedStyle(div).opacity, '0.5', 'set double duration');
-  anim.effect.timing.duration = 0;
-  assert_equals(getComputedStyle(div).opacity, '1', 'set duration 0');
-  anim.effect.timing.duration = 'auto';
-  assert_equals(getComputedStyle(div).opacity, '1', 'set duration \'auto\'');
-}, 'changed duration immediately updates its computed styles');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 1, 0 ] },
-                         { duration: 10000, endDelay: 1000, fill: 'none' });
-
-  anim.currentTime = 9000;
-  assert_equals(getComputedStyle(div).opacity, '0.1',
-                'set currentTime during duration');
-
-  anim.currentTime = 10900;
-  assert_equals(getComputedStyle(div).opacity, '1',
-                'set currentTime during endDelay');
-
-  anim.currentTime = 11100;
-  assert_equals(getComputedStyle(div).opacity, '1',
-                'set currentTime after endDelay');
-}, 'change currentTime when fill is none and endDelay is positive');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 1, 0 ] },
-                         { duration: 10000,
-                           endDelay: 1000,
-                           fill: 'forwards' });
-  anim.currentTime = 5000;
-  assert_equals(getComputedStyle(div).opacity, '0.5',
-                'set currentTime during duration');
-
-  anim.currentTime = 9999;
-  assert_equals(getComputedStyle(div).opacity, '0.0001',
-                'set currentTime just a little before duration');
-
-  anim.currentTime = 10900;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'set currentTime during endDelay');
-
-  anim.currentTime = 11100;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'set currentTime after endDelay');
-}, 'change currentTime when fill forwards and endDelay is positive');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 1, 0 ] },
-                         { duration: 10000, endDelay: -5000, fill: 'none' });
-
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(div).opacity, '0.9',
-                'set currentTime before endTime');
-
-  anim.currentTime = 10000;
-  assert_equals(getComputedStyle(div).opacity, '1',
-                'set currentTime after endTime');
-}, 'change currentTime when fill none and endDelay is negative');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 1, 0 ] },
-                         { duration: 10000,
-                           endDelay: -5000,
-                           fill: 'forwards' });
-
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(div).opacity, '0.9',
-                'set currentTime before endTime');
-
-  anim.currentTime = 5000;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'set currentTime same as endTime');
-
-  anim.currentTime = 9999;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'set currentTime during duration');
-
-  anim.currentTime = 10000;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'set currentTime after endTime');
-}, 'change currentTime when fill forwards and endDelay is negative');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart-expected.txt
deleted file mode 100644
index bf47a38dc..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart-expected.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This is a testharness.js-based test.
-FAIL Test that changing the iterationStart affects computed timing when backwards-filling anim.effect.getComputedTiming is not a function
-FAIL Test that changing the iterationStart affects computed timing during the active phase anim.effect.getComputedTiming is not a function
-FAIL Test that changing the iterationStart affects computed timing when forwards-filling anim.effect.getComputedTiming is not a function
-FAIL Test invalid iterationStart value assert_throws: function "function () {
-                  anim.effect.timing.iterat..." did not throw
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart.html
deleted file mode 100644
index 21e73e1..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart.html
+++ /dev/null
@@ -1,72 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>iterationStart tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffecttiming-iterationstart">
-<link rel="author" title="Daisuke Akatsuka" href="mailto:daisuke@mozilla-japan.org">
-<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 div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { iterationStart: 0.2,
-                           iterations: 1,
-                           fill: 'both',
-                           duration: 100,
-                           delay: 1 });
-  anim.effect.timing.iterationStart = 2.5;
-  assert_equals(anim.effect.getComputedTiming().progress, 0.5);
-  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
-}, 'Test that changing the iterationStart affects computed timing ' +
-   'when backwards-filling');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { iterationStart: 0.2,
-                           iterations: 1,
-                           fill: 'both',
-                           duration: 100,
-                           delay: 0 });
-  anim.effect.timing.iterationStart = 2.5;
-  assert_equals(anim.effect.getComputedTiming().progress, 0.5);
-  assert_equals(anim.effect.getComputedTiming().currentIteration, 2);
-}, 'Test that changing the iterationStart affects computed timing ' +
-   'during the active phase');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] },
-                         { iterationStart: 0.2,
-                           iterations: 1,
-                           fill: 'both',
-                           duration: 100,
-                           delay: 0 });
-  anim.finish();
-  anim.effect.timing.iterationStart = 2.5;
-  assert_equals(anim.effect.getComputedTiming().progress, 0.5);
-  assert_equals(anim.effect.getComputedTiming().currentIteration, 3);
-}, 'Test that changing the iterationStart affects computed timing ' +
-   'when forwards-filling');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, 100);
-  assert_throws({ name: 'TypeError' },
-                function() {
-                  anim.effect.timing.iterationStart = -1;
-                });
-  assert_throws({ name: 'TypeError' },
-                function() {
-                  div.animate({ opacity: [ 0, 1 ] },
-                              { iterationStart: -1 });
-                });
-}, 'Test invalid iterationStart value');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after-expected.txt
deleted file mode 100644
index 80d9de7b..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.after() does nothing if the node has no parent animation group. HierarchyRequestError is not thrown in call node.after(null) Animation is not defined
-FAIL AnimationNode.after() does nothing if the node has no parent animation group. No HierarchyRequestError is thrown if the node is inserted after itself Animation is not defined
-FAIL AnimationNode.after() does nothing if there is no parent animation group Animation is not defined
-FAIL HierarchyRequestError is thrown if node is inserted after itself AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if direct parent is inserted after the node AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if an inclusive ancestor is inserted after the node AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if an inclusive ancestor is inserted after the node. Test several arguments in after() call AnimationGroup is not defined
-FAIL AnimationNode.after() inserts nodes after this node AnimationGroup is not defined
-FAIL AnimationNode.after() inserts nodes after this node. Inserted node is on the same level in the tree AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts node after this node even if inserted node is already after this one AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts node after this node. The previous position of the inserted node is deeper in the tree than current node AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts node after this node. The previous position of the inserted node is shallower in the tree than current node, but not ancestor AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts several nodes after this node AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts several nodes after this node, duplicate nodes are ignored AnimationGroup is not defined
-FAIL Test AnimationNode.after() inserts several nodes after this node, check insertion order AnimationGroup is not defined
-FAIL Test AnimationNode.after() disassociates the inserted node from the player, if node is directly associated with a player AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after.html
deleted file mode 100644
index 3db07eee..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after.html
+++ /dev/null
@@ -1,419 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode after() method tests</title>
-<meta name="assert" content="Inserts nodes after this animation node">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-after">
-<link rel="help" href="http://w3c.github.io/web-animations/#insert-children">
-<link rel="help" href="http://w3c.github.io/web-animations/#remove-an-animation-node">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-// Test step 1. If there is no parent animation group, terminate these steps.
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.after(null);
-        } catch(e) {
-            assert_unreached(type(node) + '.after(null) throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.after() does nothing if the node has no parent animation group. ' +
-    'HierarchyRequestError is not thrown in call node.after(null)');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.after(node);
-        } catch(e) {
-            assert_unreached(type(node) + '.after() throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.after() does nothing if the node has no parent animation group. ' +
-    'No HierarchyRequestError is thrown if the node is inserted after itself');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    var node2 = newAnimation(createDiv(this));
-    nodes.forEach(function(node1) {
-        node1.after(node2);
-
-        assert_equals(node1.nextSibling, null, type(node1) + '.after() should do nothing ' +
-            'if the node has no parent animation group');
-        assert_equals(node2.previousSibling, null, type(node1) + '.after() should do nothing ' +
-            'if the node has no parent animation group');
-    });
-}, 'AnimationNode.after() does nothing if there is no parent animation group');
-
-// Test step 2. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.after(node);
-            }, type(node) + '.after() should throw HierarchyRequestError ' +
-                'if inserting node after itself');
-            assert_equals(node.parent, parent, type(node) + '.after() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.after() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if node is inserted after itself');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.after(parent);
-            }, type(node) + '.after() should throw HierarchyRequestError ' +
-                'if inserting node\'s parent');
-            assert_equals(node.parent, parent, type(node) + '.after() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.after() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if direct parent is inserted after the node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent1 = new parentCtor([node]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.after(parent3);
-            }, type(node) + '.after() should throw HierarchyRequestError ' +
-                'if inserting node\'s ancestor');
-            assert_equals(node.parent, parent1, type(node) + '.after() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node], type(node) + '.after() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node) + '.after() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node) + '.after() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if an inclusive ancestor is inserted after the node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-            var parent5 = new ParentCtor([node3]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node1.after(node3, parent3);
-            }, type(node1) + '.after() should throw HierarchyRequestError ' +
-                'if inserting node\'s parent');
-            assert_equals(node1.parent, parent1, type(node1) + '.after() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node1, node2], type(node1) + '.after() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node1) + '.after() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node1) + '.after() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-            assert_equals(node3.parent, parent5, type(node1) + '.after() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent5.children, [node3], type(node1) + '.after() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if an inclusive ancestor is inserted after the node. ' +
-    'Test several arguments in after() call');
-
-// Test step 3 and 4.
-// 3. Let reference child be the next sibling of this animation node not in nodes.
-// 4. Insert nodes before reference child.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-
-            node1.after(node2);
-
-            assert_equals(node2.previousSibling, node1, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node2.parent, parent, 'Node should be inserted into the tree');
-            assert_equals(node1.nextSibling, node2, 'Node should be inserted into the tree ' +
-                'after this node');
-            assert_equals(parent.children, [node1, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'AnimationNode.after() inserts nodes after this node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.after(node1);
-
-            assert_equals(node2.previousSibling, null, type(node2) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node2.nextSibling, node1, 'Node should be inserted into the tree ' +
-                'after this node');
-            assert_equals(node1.previousSibling, node2, type(node2) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node1.nextSibling, null, 'Node should be inserted into the tree ' +
-                'after this node');
-            assert_equals(parent.children, [node2, node1], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'AnimationNode.after() inserts nodes after this node. Inserted node is on the same ' +
-    'level in the tree');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.after(node2);
-
-            assert_equals(node1.nextSibling, node2, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node2.previousSibling, node1, 'Node should be inserted into the tree ' +
-                'after this node');
-            assert_equals(parent.children, [node1, node2], parentCtor.name +
-                '.children should not be changed');
-        });
-    });
-}, 'Test AnimationNode.after() inserts node after this node even if inserted ' +
-    'node is already after this one');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node3) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node3.after(node1);
-
-            assert_equals(node1.nextSibling, parent1, type(node3) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node1.parent, parent2, 'Parent group of the inserted node should be changed');
-            assert_equals(node1.previousSibling, node3, 'Node should be inserted into the tree ' +
-                'after this node');
-
-            assert_equals(node3.nextSibling, node1, type(node3) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(parent1.previousSibling, node1, type(node3) + '.after() should insert ' +
-                'nodes after this node');
-
-            assert_equals(node2.previousSibling, null, 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent1.children, [node2], 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent2.children, [node1, node3, parent1, node4], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.after() inserts node after this node. The previous position ' +
-    'of the inserted node is deeper in the tree than current node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node1.after(node4);
-
-            assert_equals(node4.nextSibling, node2, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.parent, parent1, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node1, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-
-            assert_equals(node1.nextSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node2.previousSibling, node4, 'Node should be inserted into the tree ' +
-                'after this node');
-
-            assert_equals(parent1.nextSibling, null, 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent1.children, [node1, node4, node2], parentCtor.name +
-                '.children should be updated');
-            assert_array_equals(parent2.children, [node3, parent1], 'Inserted node should be ' +
-                'removed from its previous position in the tree');
-        });
-    });
-}, 'Test AnimationNode.after() inserts node after this node. The previous position ' +
-    'of the inserted node is shallower in the tree than current node, but not ancestor');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.after(node3, node4);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.nextSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.nextSibling, node2, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_array_equals(parent.children, [node1, node3, node4, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.after() inserts several nodes after this node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.after(node3, node4, node3, node4);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.nextSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.nextSibling, node2, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_array_equals(parent.children, [node1, node3, node4, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.after() inserts several nodes after this node, duplicate nodes are ignored');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.after(node3, node4, node3);
-
-            assert_equals(node1.nextSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.previousSibling, node1, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.nextSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node3.previousSibling, node4, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.nextSibling, node2, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node3, type(node1) + '.after() should insert ' +
-                'nodes after this node');
-            assert_array_equals(parent.children, [node1, node4, node3, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.after() inserts several nodes after this node, check insertion order');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            var player = document.timeline.play(node2);
-
-            assert_equals(player.source, node2, 'The node should be associated with its player');
-            node1.after(node2);
-            assert_equals(player.source, null, 'The node should be disassociated from its player');
-        });
-    });
-}, 'Test AnimationNode.after() disassociates the inserted node from the player, ' +
-    'if node is directly associated with a player');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before-expected.txt
deleted file mode 100644
index f2e2ebf4..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before-expected.txt
+++ /dev/null
@@ -1,19 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.before() does nothing if the node has no parent animation group. HierarchyRequestError is not thrown in call node.before(null) Animation is not defined
-FAIL AnimationNode.before() does nothing if the node has no parent animation group. No HierarchyRequestError is thrown if the node is inserted before itself Animation is not defined
-FAIL AnimationNode.before() does nothing if there is no parent animation group Animation is not defined
-FAIL HierarchyRequestError is thrown if node is inserted before itself AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if direct parent is inserted before the node AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if an inclusive ancestor is inserted before the node AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if an inclusive ancestor is inserted before the node. Test several arguments in before() call AnimationGroup is not defined
-FAIL AnimationNode.before() inserts nodes before this node AnimationGroup is not defined
-FAIL AnimationNode.before() inserts nodes before this node. Inserted node is on the same level in the tree AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts node before this node even if inserted node is already before this one AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts node before this node. The previous position of the inserted node is deeper in the tree than current node AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts node before this node. The previous position of the inserted node is shallower in the tree than current node, but not ancestor AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts several nodes before this node AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts several nodes before this node, duplicate nodes are ignored AnimationGroup is not defined
-FAIL Test AnimationNode.before() inserts several nodes before this node, check insertion order AnimationGroup is not defined
-FAIL Test AnimationNode.before() disassociates the inserted node from the player, if node is directly associated with a player AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before.html
deleted file mode 100644
index 22caa02..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before.html
+++ /dev/null
@@ -1,418 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode before() method tests</title>
-<meta name="assert" content="Inserts nodes before this animation node.">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-before">
-<link rel="help" href="http://w3c.github.io/web-animations/#insert-children">
-<link rel="help" href="http://w3c.github.io/web-animations/#remove-an-animation-node">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-// Test step 1. If there is no parent animation group, terminate these steps.
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.before(null);
-        } catch(e) {
-            assert_unreached(type(node) + '.before(null) throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.before() does nothing if the node has no parent animation group. ' +
-    'HierarchyRequestError is not thrown in call node.before(null)');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.before(node);
-        } catch(e) {
-            assert_unreached(type(node) + '.before() throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.before() does nothing if the node has no parent animation group. ' +
-    'No HierarchyRequestError is thrown if the node is inserted before itself');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    var node2 = newAnimation(createDiv(this));
-    nodes.forEach(function(node1) {
-        node1.before(node2);
-
-        assert_equals(node1.nextSibling, null, type(node1) + '.before() should do nothing ' +
-            'if the node has no parent animation group');
-        assert_equals(node2.previousSibling, null, type(node1) + '.before() should do nothing ' +
-            'if the node has no parent animation group');
-    });
-}, 'AnimationNode.before() does nothing if there is no parent animation group');
-
-// Test step 2. If any of the animation nodes in nodes is an inclusive ancestor of this animation node throw a HierarchyRequestError exception and terminate these steps.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.before(node);
-            }, type(node) + '.before() should throw HierarchyRequestError ' +
-                'if inserting node before itself');
-            assert_equals(node.parent, parent, type(node) + '.before() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.before() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-
-        });
-    });
-}, 'HierarchyRequestError is thrown if node is inserted before itself');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.before(parent);
-            }, type(node) + '.before() should throw HierarchyRequestError ' +
-                'if inserting node\'s parent');
-            assert_equals(node.parent, parent, type(node) + '.before() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.before() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if direct parent is inserted before the node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent1 = new parentCtor([node]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.before(parent4);
-            }, type(node) + '.before() should throw HierarchyRequestError ' +
-                'if inserting node\'s ancestor');
-            assert_equals(node.parent, parent1, type(node) + '.before() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node], type(node) + '.before() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node) + '.before() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node) + '.before() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if an inclusive ancestor is inserted before the node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-            var parent5 = new ParentCtor([node3]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node1.before(node3, parent3);
-            }, type(node1) + '.before() should throw HierarchyRequestError ' +
-                'if inserting node\'s parent');
-            assert_equals(node1.parent, parent1, type(node1) + '.before() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node1, node2], type(node1) + '.before() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node1) + '.before() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node1) + '.before() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-            assert_equals(node3.parent, parent5, type(node1) + '.before() should not change ' +
-                'parent attribute of inserted node before throwing HierarchyRequestError');
-            assert_array_equals(parent5.children, [node3], type(node1) + '.before() ' +
-                'should not change inserted node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if an inclusive ancestor is inserted before the node. ' +
-    'Test several arguments in before() call');
-
-// Test step 3. Insert nodes before this animation node.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-
-            node1.before(node2);
-
-            assert_equals(node1.previousSibling, node2, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node2.parent, parent, 'Node should be inserted into the tree');
-            assert_equals(node2.nextSibling, node1, 'Node should be inserted into the tree ' +
-                'before this node');
-            assert_equals(parent.children, [node2, node1], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'AnimationNode.before() inserts nodes before this node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.before(node2);
-
-            assert_equals(node2.previousSibling, null, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node2.nextSibling, node1, 'Node should be inserted into the tree ' +
-                'before this node');
-            assert_equals(node1.previousSibling, node2, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node1.nextSibling, null, 'Node should be inserted into the tree ' +
-                'before this node');
-            assert_equals(parent.children, [node2, node1], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'AnimationNode.before() inserts nodes before this node. Inserted node is on the same ' +
-    'level in the tree');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.before(node1);
-
-            assert_equals(node1.nextSibling, node2, type(node2) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node2.previousSibling, node1, 'Node should be inserted into the tree ' +
-                'before this node');
-            assert_equals(parent.children, [node1, node2], parentCtor.name +
-                '.children should not be changed');
-        });
-    });
-}, 'Test AnimationNode.before() inserts node before this node even if inserted ' +
-    'node is already before this one');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node4) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node4.before(node1);
-
-            assert_equals(node1.nextSibling, parent1, type(node4) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node1.parent, parent2, 'Parent group of the inserted node should be changed');
-            assert_equals(node1.previousSibling, parent1, 'Node should be inserted into the tree ' +
-                'before this node');
-
-            assert_equals(parent1.nextSibling, node1, type(node4) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.previousSibling, node1, type(node4) + '.before() should insert ' +
-                'nodes before this node');
-
-            assert_equals(node2.previousSibling, null, 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent1.children, [node2], 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent2.children, [node3, parent1, node1, node4], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.before() inserts node before this node. The previous position ' +
-    'of the inserted node is deeper in the tree than current node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node2.before(node4);
-
-            assert_equals(node4.nextSibling, node2, type(node2) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.parent, parent1, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node1, type(node2) + '.before() should insert ' +
-                'nodes before this node');
-
-            assert_equals(node1.nextSibling, node4, type(node2) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node2.previousSibling, node4, 'Node should be inserted into the tree ' +
-                'before this node');
-
-            assert_equals(parent1.nextSibling, null, 'Inserted node should be removed from its ' +
-                'previous position in the tree');
-            assert_array_equals(parent1.children, [node1, node4, node2], parentCtor.name +
-                '.children should be updated');
-            assert_array_equals(parent2.children, [node3, parent1], 'Inserted node should be ' +
-                'removed from its previous position in the tree');
-        });
-    });
-}, 'Test AnimationNode.before() inserts node before this node. The previous position ' +
-    'of the inserted node is shallower in the tree than current node, but not ancestor');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.before(node3, node4);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.nextSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.nextSibling, node2, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_array_equals(parent.children, [node1, node3, node4, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.before() inserts several nodes before this node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.before(node3, node4, node3, node4);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.nextSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.nextSibling, node2, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_array_equals(parent.children, [node1, node3, node4, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.before() inserts several nodes before this node, duplicate nodes are ignored');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.before(node3, node4, node3);
-
-            assert_equals(node1.nextSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.previousSibling, node1, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.nextSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node3.previousSibling, node4, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.nextSibling, node2, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node2.previousSibling, node3, type(node1) + '.before() should insert ' +
-                'nodes before this node');
-            assert_array_equals(parent.children, [node1, node4, node3, node2], parentCtor.name +
-                '.children should be updated');
-        });
-    });
-}, 'Test AnimationNode.before() inserts several nodes before this node, check insertion order');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            var player = document.timeline.play(node2);
-
-            assert_equals(player.source, node2, 'The node should be associated with its player');
-            node1.before(node2);
-            assert_equals(player.source, null, 'The node should be disassociated from its player');
-        });
-    });
-}, 'Test AnimationNode.before() disassociates the inserted node from the player, ' +
-    'if node is directly associated with a player');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling-expected.txt
deleted file mode 100644
index 9625203..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling-expected.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.nextSibling is null if the node is standalone Animation is not defined
-FAIL AnimationNode.nextSibling is null if the node is the only child of its parent AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node. Test first child AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node. Test second child AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node. Test tree structure with AnimationGroup Animation is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node. Test tree structure with AnimationSequence Animation is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method before() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is removed by method before() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, several nodes are added by method before() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method after() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is removed by method after() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, several nodes are added by method after() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method replace() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is removed by method replace() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, several nodes are added by method replace() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method remove() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is removed by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, several nodes are added by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is changed by method AnimationGroup.append() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, the next sibling is removed by method AnimationGroup.append() AnimationGroup is not defined
-FAIL AnimationNode.nextSibling returns next sibling of this animation node, several nodes are added by method AnimationGroup.append() AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling.html
deleted file mode 100644
index 8a6b4a8..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling.html
+++ /dev/null
@@ -1,503 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode nextSibling attribute tests</title>
-<meta name="assert" content="The next sibling of this animation node">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-nextsibling">
-<link rel="help" href="http://www.w3.org/TR/dom/#concept-tree-next-sibling">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        assert_equals(node.nextSibling, null, type(node) + '.nextSibling should be null');
-    });
-}, 'AnimationNode.nextSibling is null if the node is standalone');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_equals(node.nextSibling, null, type(node) + '.nextSibling ' +
-                'should be null');
-        });
-    });
-}, 'AnimationNode.nextSibling is null if the node is the only child of its parent');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            assert_equals(node1.nextSibling, node2, type(node1) + '.nextSibling should return ' +
-                'next sibling of this animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.nextSibling should be null');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node. Test first child');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            assert_equals(node1.nextSibling, node2, type(node1) + '.nextSibling should return ' +
-                'next sibling of this animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.nextSibling should be null');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node. Test second child');
-
-test(function() {
-    var node1 = newAnimation(createDiv(this));
-    var node2 = newAnimation(createDiv(this));
-    var node3 = newAnimation(createDiv(this));
-    var node4 = newAnimation(createDiv(this));
-    var node5 = newAnimation(createDiv(this));
-    var node6 = newAnimation(createDiv(this));
-    var node7 = new AnimationGroup([node3, node4]);
-    var node8 = new AnimationGroup([node5, node6]);
-    var node9 = newAnimation(createDiv(this));
-    var group = new AnimationGroup([node1, node2, node7, node8, node9]);
-
-    assert_equals(group.nextSibling, null, 'AnimationNode.nextSibling should return ' +
-        'null (root node)');
-    assert_equals(node1.nextSibling, node2, 'AnimationNode.nextSibling should return ' +
-        'next sibling for the first node in the group');
-    assert_equals(node2.nextSibling, node7, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node');
-    assert_equals(node3.nextSibling, node4, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first node in the nested group)');
-    assert_equals(node4.nextSibling, null, 'AnimationNode.nextSibling should be null ' +
-        'for the last node in the nested group');
-	assert_equals(node5.nextSibling, node6, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first node in the second nested group)');
-    assert_equals(node6.nextSibling, null, 'AnimationNode.nextSibling should be null ' +
-        'for the last node in the second nested group');
-    assert_equals(node7.nextSibling, node8, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first nested group)');
-    assert_equals(node8.nextSibling, node9, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (second nested group)');
-    assert_equals(node9.nextSibling, null, 'AnimationNode.nextSibling should return ' +
-        'null (the last node)');
-}, 'AnimationNode.nextSibling returns next sibling of this animation node. Test ' +
-    'tree structure with AnimationGroup');
-
-test(function() {
-    var node1 = newAnimation(createDiv(this));
-    var node2 = newAnimation(createDiv(this));
-    var node3 = newAnimation(createDiv(this));
-    var node4 = newAnimation(createDiv(this));
-    var node5 = newAnimation(createDiv(this));
-    var node6 = newAnimation(createDiv(this));
-    var node7 = new AnimationSequence([node3, node4]);
-    var node8 = new AnimationSequence([node5, node6]);
-    var node9 = newAnimation(createDiv(this));
-    var sequence = new AnimationSequence([node1, node2, node7, node8, node9]);
-
-    assert_equals(sequence.nextSibling, null, 'AnimationNode.nextSibling should return ' +
-        'null (root node)');
-    assert_equals(node1.nextSibling, node2, 'AnimationNode.nextSibling should return ' +
-        'next sibling for the first node in the sequence');
-    assert_equals(node2.nextSibling, node7, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node');
-    assert_equals(node3.nextSibling, node4, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first node in the nested sequence)');
-    assert_equals(node4.nextSibling, null, 'AnimationNode.nextSibling should be null ' +
-        'for the last node in the nested sequence');
-	assert_equals(node5.nextSibling, node6, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first node in the second nested sequence)');
-    assert_equals(node6.nextSibling, null, 'AnimationNode.nextSibling should be null ' +
-        'for the last node in the second nested sequence');
-    assert_equals(node7.nextSibling, node8, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (first nested sequence)');
-    assert_equals(node8.nextSibling, node9, 'AnimationNode.nextSibling should return ' +
-        'next sibling of this animation node (second nested sequence)');
-    assert_equals(node9.nextSibling, null, 'AnimationNode.nextSibling should return ' +
-        'null (the last node)');
-}, 'AnimationNode.nextSibling returns next sibling of this animation node. Test ' +
-    'tree structure with AnimationSequence');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-            node2.before(node3);
-
-            assert_equals(node1.nextSibling, node3, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node2, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node3) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            node3.before(node2);
-
-            assert_equals(node1.nextSibling, null, type(node3) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, node3, type(node3) + '.before() should update ' +
-                'next sibling of animation node');
-        });
-    });
-},  'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is removed by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = new AnimationGroup([]);
-            var node5 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2]);
-            node2.before(node3, node4, node5);
-
-            assert_equals(node1.nextSibling, node3, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node4, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node4.nextSibling, node5, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node5.nextSibling, node2, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.before() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'several nodes are added by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-            node1.after(node3);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node2, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node3) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            node3.after(node2);
-
-            assert_equals(node1.nextSibling, null, type(node3) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node2, type(node3) + '.after() should update ' +
-                'next sibling of animation node');
-        });
-    });
-},  'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is removed by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = new AnimationGroup([]);
-            var node5 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2]);
-            node1.after(node3, node4, node5);
-
-            assert_equals(node1.nextSibling, node3, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node4, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node4.nextSibling, node5, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node5.nextSibling, node2, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node1) + '.after() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'several nodes are added by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.replace(node4);
-
-            assert_equals(node1.nextSibling, node4, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node4.nextSibling, node3, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node4) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2, node3]);
-            var parent2 = new parentCtor([node4]);
-
-            node4.replace(node2);
-
-            assert_equals(node1.nextSibling, node3, type(node4) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node4) + '.replace() should update ' +
-                'next sibling of animation node');
-        });
-    });
-},  'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is removed by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var node5 = new AnimationGroup([]);
-            var node6 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.replace(node4, node5, node6);
-
-            assert_equals(node1.nextSibling, node4, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node4.nextSibling, node5, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node5.nextSibling, node6, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node6.nextSibling, node3, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'several nodes are added by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.remove();
-
-            assert_equals(node1.nextSibling, node3, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, type(node2) + '.replace() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method remove()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            parent.prepend(node2);
-
-            assert_equals(node2.nextSibling, node1, parentCtor.name + '.prepend() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            parent2.prepend(node2);
-
-            assert_equals(node1.nextSibling, null, parentCtor.name + '.prepend() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, node3, parentCtor.name + '.prepend() should update ' +
-                'next sibling of animation node');
-        });
-    });
-},  'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is removed by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var node1 = newAnimation(createDiv(test));
-        var node2 = new AnimationGroup([]);
-        var node3 = new AnimationSequence([]);
-        var node4 = newAnimation(createDiv(test));
-        var parent = new parentCtor([node1]);
-        parent.prepend(node2, node3, node4);
-
-        assert_equals(node2.nextSibling, node3, parentCtor.name + '.prepend() should update ' +
-            'next sibling of animation node');
-        assert_equals(node3.nextSibling, node4, parentCtor.name + '.prepend() should update ' +
-            'next sibling of animation node');
-        assert_equals(node4.nextSibling, node1, parentCtor.name + '.prepend() should update ' +
-            'next sibling of animation node');
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'several nodes are added by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            parent.append(node2);
-
-            assert_equals(node1.nextSibling, node2, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, null, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is changed by method AnimationGroup.append()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            parent2.append(node2);
-
-            assert_equals(node1.nextSibling, null, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node2, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-        });
-    });
-},  'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'the next sibling is removed by method AnimationGroup.append()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = new AnimationGroup([]);
-            var node4 = new AnimationSequence([]);
-            var parent = new parentCtor([node1]);
-            parent.append(node2, node3, node4);
-
-            assert_equals(node1.nextSibling, node2, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-            assert_equals(node2.nextSibling, node3, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-            assert_equals(node3.nextSibling, node4, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-            assert_equals(node4.nextSibling, null, parentCtor.name + '.append() should update ' +
-                'next sibling of animation node');
-        });
-    });
-}, 'AnimationNode.nextSibling returns next sibling of this animation node, ' +
-    'several nodes are added by method AnimationGroup.append()');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent-expected.txt
deleted file mode 100644
index 0602142..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent-expected.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.parent is null if animation node does not have a parent animation group Animation is not defined
-FAIL AnimationNode.parent returns parent animation group of this animation node AnimationGroup is not defined
-FAIL AnimationNode.parent returns parent animation group of this animation node. The group has several children nodes AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent.html
deleted file mode 100644
index 1c4ac6f..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent.html
+++ /dev/null
@@ -1,53 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode parent attribute tests</title>
-<meta name="assert" content="The parent animation group of this animation node or null if this animation node does not have a parent animation group">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-parent">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        assert_equals(node.parent, null, type(node) + '.parent should be null');
-    });
-}, 'AnimationNode.parent is null if animation node does not have a parent animation group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_equals(node.parent, parent, type(node) + '.parent should return ' +
-                'parent animation group of this animation node');
-        });
-    });
-}, 'AnimationNode.parent returns parent animation group of this animation node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        var parent = new parentCtor([nodes[0], nodes[1], nodes[2]]);
-        nodes.forEach(function(node) {
-            assert_equals(node.parent, parent, type(node) + '.parent should return ' +
-                'parent animation group of this animation node');
-        });
-    });
-}, 'AnimationNode.parent returns parent animation group of this animation node. ' +
-    'The group has several children nodes');
-
-// The rest is tested in mutator methods: AnimationNode.before(), AnimationNode.after(),
-// AnimationNode.replace(), AnimationNode.remove(),
-// AnimationGroup.prepend(), AnimationGroup.append(), AnimationGroup.clone()
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling-expected.txt
deleted file mode 100644
index 3a790fa..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling-expected.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.previousSibling is null if the node is standalone Animation is not defined
-FAIL AnimationNode.previousSibling is null if the node is the only child of its parent AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node. Test first child AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node. Test second child AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node. Test tree structure with AnimationGroup Animation is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node. Test tree structure with AnimationSequence Animation is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method before() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is removed by method before() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, several nodes are added by method before() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method after() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is removed by method after() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, several nodes are added by method after() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method replace() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is removed by method replace() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, several nodes are added by method replace() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method remove() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is removed by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, several nodes are added by method AnimationGroup.prepend() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is changed by method AnimationGroup.append() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, the previous sibling is removed by method AnimationGroup.append() AnimationGroup is not defined
-FAIL AnimationNode.previousSibling returns previous sibling of this animation node, several nodes are added by method AnimationGroup.append() AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling.html
deleted file mode 100644
index 16f1936..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling.html
+++ /dev/null
@@ -1,511 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode previousSibling attribute tests</title>
-<meta name="assert" content="The previous sibling of this animation node">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-previoussibling">
-<link rel="help" href="http://www.w3.org/TR/dom/#concept-tree-previous-sibling">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-test(function() {
-    var nodes = [
-        newAnimation(createDiv(this)),
-        new AnimationGroup([]),
-        new AnimationSequence([])
-    ];
-    nodes.forEach(function(node) {
-        assert_equals(node.previousSibling, null, type(node) + '.previousSibling should be null');
-    });
-}, 'AnimationNode.previousSibling is null if the node is standalone');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_equals(node.previousSibling, null, type(node) + '.previousSibling ' +
-                'should be null');
-        });
-    });
-}, 'AnimationNode.previousSibling is null if the node is the only child of its parent');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            assert_equals(node1.previousSibling, null, type(node1) + '.previousSibling should be null');
-            assert_equals(node2.previousSibling, node1, type(node2) + '.previousSibling should return ' +
-                'previous sibling of this animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node. Test first child');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            assert_equals(node1.previousSibling, null, type(node1) + '.previousSibling should be null');
-            assert_equals(node2.previousSibling, node1, type(node2) + '.previousSibling should return ' +
-                'previous sibling of this animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node. Test second child');
-
-test(function() {
-    var node1 = newAnimation(createDiv(this));
-    var node2 = newAnimation(createDiv(this));
-    var node3 = newAnimation(createDiv(this));
-    var node4 = newAnimation(createDiv(this));
-    var node5 = newAnimation(createDiv(this));
-    var node6 = newAnimation(createDiv(this));
-    var node7 = new AnimationGroup([node3, node4]);
-    var node8 = new AnimationGroup([node5, node6]);
-    var node9 = newAnimation(createDiv(this));
-    var group = new AnimationGroup([node1, node2, node7, node8, node9]);
-
-    assert_equals(group.previousSibling, null, 'AnimationNode.previousSibling should return ' +
-        'null (root node)');
-    assert_equals(node1.previousSibling, null, 'AnimationNode.previousSibling should return ' +
-        'null for the first node in the group');
-    assert_equals(node2.previousSibling, node1, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node');
-    assert_equals(node3.previousSibling, null, 'AnimationNode.previousSibling should be null ' +
-        'for the first node in the nested group');
-    assert_equals(node4.previousSibling, node3, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first node in the nested group)');
-    assert_equals(node5.previousSibling, null, 'AnimationNode.previousSibling should be null ' +
-        'for the first node in the second nested group');
-	assert_equals(node6.previousSibling, node5, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first node in the second nested group)');
-    assert_equals(node7.previousSibling, node2, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first nested group)');
-    assert_equals(node8.previousSibling, node7, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (second nested group)');
-    assert_equals(node9.previousSibling, node8, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node');
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node. Test ' +
-    'tree structure with AnimationGroup');
-
-test(function() {
-    var node1 = newAnimation(createDiv(this));
-    var node2 = newAnimation(createDiv(this));
-    var node3 = newAnimation(createDiv(this));
-    var node4 = newAnimation(createDiv(this));
-    var node5 = newAnimation(createDiv(this));
-    var node6 = newAnimation(createDiv(this));
-    var node7 = new AnimationSequence([node3, node4]);
-    var node8 = new AnimationSequence([node5, node6]);
-    var node9 = newAnimation(createDiv(this));
-    var sequence = new AnimationSequence([node1, node2, node7, node8, node9]);
-
-    assert_equals(sequence.previousSibling, null, 'AnimationNode.previousSibling should return ' +
-        'null (root node)');
-    assert_equals(node1.previousSibling, null, 'AnimationNode.previousSibling should return ' +
-        'null for the first node in the group');
-    assert_equals(node2.previousSibling, node1, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node');
-    assert_equals(node3.previousSibling, null, 'AnimationNode.previousSibling should be null ' +
-        'for the first node in the nested group');
-    assert_equals(node4.previousSibling, node3, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first node in the nested group)');
-    assert_equals(node5.previousSibling, null, 'AnimationNode.previousSibling should be null ' +
-        'for the first node in the second nested group');
-	assert_equals(node6.previousSibling, node5, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first node in the second nested group)');
-    assert_equals(node7.previousSibling, node2, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (first nested group)');
-    assert_equals(node8.previousSibling, node7, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node (second nested group)');
-    assert_equals(node9.previousSibling, node8, 'AnimationNode.previousSibling should return ' +
-        'previous sibling of this animation node');
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node. Test ' +
-    'tree structure with AnimationSequence');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-            node2.before(node3);
-
-            assert_equals(node1.previousSibling, null, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, node3, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node3) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            node3.before(node1);
-
-            assert_equals(node1.previousSibling, null, type(node3) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node3) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, type(node3) + '.before() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-},  'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is removed by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = new AnimationGroup([]);
-            var node5 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2]);
-            node2.before(node3, node4, node5);
-
-            assert_equals(node1.previousSibling, null, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node4.previousSibling, node3, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node5.previousSibling, node4, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, node5, type(node2) + '.before() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'several nodes are added by method before()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-            node1.after(node3);
-
-            assert_equals(node1.previousSibling, null, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, node3, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node3) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            node3.after(node1);
-
-            assert_equals(node1.previousSibling, node3, type(node3) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node3) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, null, type(node3) + '.after() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-},  'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is removed by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = new AnimationGroup([]);
-            var node5 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2]);
-            node1.after(node3, node4, node5);
-
-            assert_equals(node1.previousSibling, null, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node4.previousSibling, node3, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node5.previousSibling, node4, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, node5, type(node1) + '.after() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'several nodes are added by method after()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.replace(node4);
-
-            assert_equals(node4.previousSibling, node1, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node4, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node4) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2, node3]);
-            var parent2 = new parentCtor([node4]);
-
-            node4.replace(node2);
-
-            assert_equals(node3.previousSibling, node1, type(node4) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node4) + '.replace() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-},  'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is removed by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var node5 = new AnimationGroup([]);
-            var node6 = new AnimationSequence([]);
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.replace(node4, node5, node6);
-
-            assert_equals(node4.previousSibling, node1, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node5.previousSibling, node4, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node6.previousSibling, node5, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node6, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'several nodes are added by method replace()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-            node2.remove();
-
-            assert_equals(node3.previousSibling, node1, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, null, type(node2) + '.replace() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method remove()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            parent.prepend(node2);
-
-            assert_equals(node1.previousSibling, node2, parentCtor.name + '.prepend() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            parent2.prepend(node1);
-
-            assert_equals(node2.previousSibling, null, parentCtor.name + '.prepend() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node1, parentCtor.name + '.prepend() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-},  'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is removed by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var node1 = newAnimation(createDiv(test));
-        var node2 = new AnimationGroup([]);
-        var node3 = new AnimationSequence([]);
-        var node4 = newAnimation(createDiv(test));
-        var parent = new parentCtor([node1]);
-        parent.prepend(node2, node3, node4);
-
-        assert_equals(node2.previousSibling, null, parentCtor.name + '.prepend() should update ' +
-            'previous sibling of animation node');
-        assert_equals(node3.previousSibling, node2, parentCtor.name + '.prepend() should update ' +
-            'previous sibling of animation node');
-        assert_equals(node4.previousSibling, node3, parentCtor.name + '.prepend() should update ' +
-            'previous sibling of animation node');
-        assert_equals(node1.previousSibling, node4, parentCtor.name + '.prepend() should update ' +
-            'previous sibling of animation node');
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'several nodes are added by method AnimationGroup.prepend()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            parent.append(node2);
-
-            assert_equals(node1.previousSibling, null, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node2.previousSibling, node1, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is changed by method AnimationGroup.append()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3]);
-
-            parent2.append(node1);
-
-            assert_equals(node2.previousSibling, null, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node1.previousSibling, node3, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-},  'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'the previous sibling is removed by method AnimationGroup.append()');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var node3 = new AnimationGroup([]);
-            var node4 = new AnimationSequence([]);
-            var parent = new parentCtor([node1]);
-            parent.append(node2, node3, node4);
-
-            assert_equals(node2.previousSibling, node1, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node3.previousSibling, node2, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-            assert_equals(node4.previousSibling, node3, parentCtor.name + '.append() should update ' +
-                'previous sibling of animation node');
-        });
-    });
-}, 'AnimationNode.previousSibling returns previous sibling of this animation node, ' +
-    'several nodes are added by method AnimationGroup.append()');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove-expected.txt
deleted file mode 100644
index 46be5d3..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove-expected.txt
+++ /dev/null
@@ -1,12 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.remove() does nothing for standalone node Animation is not defined
-FAIL AnimationNode.remove() removes node from the parent animation group. Removed node is the only node in the tree AnimationGroup is not defined
-FAIL AnimationNode.remove() removes node from the parent animation group. Remove the first node in the group AnimationGroup is not defined
-FAIL AnimationNode.remove() removes node from the parent animation group. Remove the last node in the group AnimationGroup is not defined
-FAIL AnimationNode.remove() removes node from the parent animation group. Remove node from the middle of the group AnimationGroup is not defined
-FAIL Test removing a node that has children AnimationGroup is not defined
-FAIL AnimationNode.remove() disassociates the node from player, if node is directly associated with a player Animation is not defined
-FAIL AnimationNode.remove() keeps parent direct association with the player AnimationGroup is not defined
-FAIL AnimationNode.remove() on the root of a non-trivial tree does not change child structure AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove.html
deleted file mode 100644
index 97f657e..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove.html
+++ /dev/null
@@ -1,239 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode remove() method tests</title>
-<meta name="assert" content="Removes this animation node from its parent animation group or player">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-remove">
-<link rel="help" href="http://w3c.github.io/web-animations/#remove-an-animation-node">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        node.remove();
-
-        assert_equals(node.parent, null, type(node) + ' node parent attribute should be null');
-    });
-}, 'AnimationNode.remove() does nothing for standalone node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-            node.remove();
-
-            assert_array_equals(parent.children, [], type(node) +
-                ' node should be removed from the parent ' + parentCtor.name);
-            assert_equals(node.parent, null, type(node) +
-                ' node parent attribute should be updated');
-        });
-    });
-}, 'AnimationNode.remove() removes node from the parent animation group. ' +
-    'Removed node is the only node in the tree');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node1.remove();
-
-            assert_array_equals(parent.children, [node2], type(node1) +
-                ' node should be removed from the parent ' + parentCtor.name);
-            assert_equals(parent.firstChild, node2, 'Parent ' + parentCtor.name +
-                ' firstChild attribute should be updated');
-            assert_equals(node1.parent, null, 'Removed ' + type(node1) +
-                ' node parent attribute should be updated');
-            assert_equals(node1.nextSibling, null, 'Removed ' + type(node1) +
-                ' node nextSibling attribute should be updated');
-            assert_equals(node2.previousSibling, null,
-                'Remaining node previousSibling attribute should be updated');
-        });
-    });
-}, 'AnimationNode.remove() removes node from the parent animation group. ' +
-    'Remove the first node in the group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.remove();
-
-            assert_array_equals(parent.children, [node1], type(node2) +
-                ' node should be removed from the parent ' + parentCtor.name);
-            assert_equals(parent.lastChild, node1, 'Parent ' + parentCtor.name +
-                ' lastChild attribute should be updated');
-            assert_equals(node2.parent, null, 'Removed ' + type(node2) +
-                ' node parent attribute should be updated');
-            assert_equals(node1.nextSibling, null,
-                'Remaining node nextSibling attribute should be updated');
-            assert_equals(node2.previousSibling, null, 'Removed ' + type(node2) +
-                ' node previousSibling attribute should be updated');
-        });
-    });
-}, 'AnimationNode.remove() removes node from the parent animation group. ' +
-    'Remove the last node in the group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-
-            node2.remove();
-
-            assert_array_equals(parent.children, [node1, node3], type(node2) +
-                ' node should be removed from the parent ' + parentCtor.name);
-            assert_equals(node2.parent, null, 'Removed ' + type(node2) +
-                ' node parent attribute should be updated');
-            assert_equals(node2.nextSibling, null, 'Removed ' + type(node2) +
-                ' node nextSibling attribute should be updated');
-            assert_equals(node2.previousSibling, null, 'Removed ' + type(node2) +
-                ' node previousSibling attribute should be updated');
-            assert_equals(node1.nextSibling, node3,
-                'Remaining node nextSibling attribute should be updated');
-            assert_equals(node3.previousSibling, node1,
-                'Remaining node previousSibling attribute should be updated');
-        });
-    });
-}, 'AnimationNode.remove() removes node from the parent animation group. ' +
-    'Remove node from the middle of the group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        parents.forEach(function(nodeCtor) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = new nodeCtor([node1, node2]);
-            var node5 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node3, node4, node5]);
-
-            node4.remove();
-
-            assert_array_equals(node4.children, [node1, node2], 'Removed ' +
-                type(node4) + ' node children should not be changed');
-            assert_array_equals(parent.children, [node3, node5], type(node4) +
-                ' node should be removed from the parent ' + parentCtor.name);
-            assert_equals(node4.parent, null, 'Removed ' + type(node2) +
-                ' node parent attribute should be updated');
-            assert_equals(node4.nextSibling, null, 'Removed ' + type(node2) +
-                ' node nextSibling attribute should be updated');
-            assert_equals(node4.previousSibling, null, 'Removed ' + type(node2) +
-                ' node previousSibling attribute should be updated');
-            assert_equals(node3.nextSibling, node5,
-                'Remaining node nextSibling attribute should be updated');
-            assert_equals(node5.previousSibling, node3,
-                'Remaining node previousSibling attribute should be updated');
-        });
-    });
-}, 'Test removing a node that has children');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        var player = document.timeline.play(node);
-        node.remove();
-
-        assert_equals(player.source, null, type(node) +
-            ' node should be disassociated from the player');
-    });
-}, 'AnimationNode.remove() disassociates the node from player, ' +
-    'if node is directly associated with a player');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-            var player = document.timeline.play(parent);
-
-            node2.remove();
-
-            assert_equals(player.source, parent, type(node2) +
-                ' parent node should remain associated with the player');
-        });
-    });
-}, 'AnimationNode.remove() keeps parent direct association with the player');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        parents.forEach(function(nodeCtor) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var node5 = new parentCtor([node4]);
-            var group1 = new AnimationGroup([node3, node5]);
-            var node6 = newAnimation(createDiv(test));
-            var node7 = new parentCtor([node6]);
-            var node8 = newAnimation(createDiv(test));
-            var sequence1 = new AnimationSequence([node7,node8]);
-            var node9 = new nodeCtor([node1, group1, node2, sequence1]);
-            var node10 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node9, node10]);
-
-            node9.remove();
-
-            assert_equals(node9.parent, null, 'Removed ' + type(node9) +
-                ' node parent attribute should be updated');
-            assert_array_equals(node9.children, [node1, group1, node2, sequence1],
-                'Removed ' + type(node9) + ' node children should not be changed');
-            for (var i = 0; i < node9.children.length; i++) {
-                assert_equals(node9.children[i].parent, node9, 'Removed ' + type(node9) +
-                    ' node children parent attribute should not be changed for child ' + i);
-            }
-            assert_array_equals(group1.children, [node3, node5],
-                'Removed ' + type(node9) + ' node grand children should not be changed');
-            for (var i = 0; i < group1.children.length; i++) {
-                assert_equals(group1.children[i].parent, group1, 'Removed ' + type(node9) +
-                    ' node grand children parent attribute should not be changed for child ' + i);
-            }
-            assert_array_equals(sequence1.children, [node7,node8],
-                'Removed ' + type(node9) + ' node grand children should not be changed');
-            for (var i = 0; i < sequence1.children.length; i++) {
-                assert_equals(sequence1.children[i].parent, sequence1, 'Removed ' + type(node9) +
-                    ' node grand children parent attribute should not be changed for child ' + i);
-            }
-            assert_array_equals(node5.children, [node4],
-                'Removed ' + type(node9) + ' node grand children should not be changed');
-            assert_equals(node4.parent, node5, 'Removed ' + type(node9) +
-                ' node grand children parent attribute should not be changed');
-            assert_array_equals(node7.children, [node6],
-                'Removed ' + type(node9) + ' node grand children should not be changed');
-            assert_equals(node6.parent, node7, 'Removed ' + type(node9) +
-                ' node grand children parent attribute should not be changed');
-        });
-    });
-}, 'AnimationNode.remove() on the root of a non-trivial tree does not change child structure');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace-expected.txt
deleted file mode 100644
index 9379969..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace-expected.txt
+++ /dev/null
@@ -1,20 +0,0 @@
-This is a testharness.js-based test.
-FAIL AnimationNode.replace(null) does nothing if node has no parent animation group Animation is not defined
-FAIL AnimationNode.replace() does nothing if node has no parent animation group. HierarchyRequestError is not thrown if the node is replacing itself Animation is not defined
-FAIL AnimationNode.replace() does nothing if node has no parent animation group Animation is not defined
-FAIL HierarchyRequestError is thrown if the node replaces itself AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if the node is replaced by its parent AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if the node is replaced by its inclusive ancestor AnimationGroup is not defined
-FAIL HierarchyRequestError is thrown if node is replaced by its inclusive ancestor. Test several arguments in replace() call AnimationGroup is not defined
-FAIL AnimationNode.replace() without arguments removes the node from the parent animation group AnimationGroup is not defined
-FAIL AnimationNode.replace() removes the node from its parent animation group AnimationGroup is not defined
-FAIL AnimationNode.replace(next sibling) removes the node from its parent animation group AnimationGroup is not defined
-FAIL AnimationNode.replace() replaces node in the parent animation group AnimationGroup is not defined
-FAIL Test AnimationNode.replace() replaces given node. The previous position of the replacement node is deeper in the tree than the current node AnimationGroup is not defined
-FAIL Test AnimationNode.replace() replaces given node. The previous position of the replacement node is shallower in the tree than current node, but is not an ancestor AnimationGroup is not defined
-FAIL Test AnimationNode.replace() replaces given node. Test several arguments AnimationGroup is not defined
-FAIL Test AnimationNode.replace() replaces given node by several nodes, duplicate nodes are ignored AnimationGroup is not defined
-FAIL Test AnimationNode.replace() replaces given node by several nodes, check replacement order AnimationGroup is not defined
-FAIL Test AnimationNode.replace() disassociates the inserted node from the player, if node is directly associated with a player AnimationGroup is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace.html
deleted file mode 100644
index f4cebc4..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace.html
+++ /dev/null
@@ -1,444 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>AnimationNode replace() method tests</title>
-<meta name="assert" content="Replaces this AnimationNode with the passed in nodes parameter">
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animationnode-replace">
-<link rel="help" href="http://w3c.github.io/web-animations/#remove-an-animation-node">
-<link rel="help" href="http://w3c.github.io/web-animations/#insert-children">
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<script>
-// Step 1. If there is no parent animation group, terminate these steps.
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.replace(null);
-        } catch(e) {
-            assert_unreached(type(node) + '.replace(null) throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.replace(null) does nothing if node has no parent animation group');
-
-test(function() {
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node) {
-        try {
-            node.replace(node);
-        } catch(e) {
-            assert_unreached(type(node) + '.replace(node) throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.replace() does nothing if node has no parent animation group. ' +
-    'HierarchyRequestError is not thrown if the node is replacing itself');
-
-test(function() {
-    var test = this;
-    var nodes = [newAnimation(createDiv(this)), new AnimationGroup([]), new AnimationSequence([])];
-    nodes.forEach(function(node1) {
-        var node2 = newAnimation(createDiv(test));
-
-        try {
-            node1.replace(node2);
-        } catch(e) {
-            assert_unreached(type(node1) + '.replace() throws unexpected exception: ' + e);
-        }
-    });
-}, 'AnimationNode.replace() does nothing if node has no parent animation group');
-
-// Step 2. If any of the animation nodes in nodes is an inclusive ancestor
-// of the parent animation group throw a HierarchyRequestError exception and terminate these steps.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.replace(node);
-            }, 'HierarchyRequestError should be thrown if ' + type(node) +
-                ' replaces itself');
-            assert_equals(node.parent, parent, type(node) + '.replace() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.replace() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if the node replaces itself');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.replace(parent);
-            }, 'HierarchyRequestError should be thrown if ' + type(node) +
-                ' is replaced by its parent ' + parentCtor.name);
-            assert_equals(node.parent, parent, type(node) + '.replace() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent.children, [node], type(node) + '.replace() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if the node is replaced by its parent');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent1 = new parentCtor([node]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node.replace(parent3);
-            }, 'HierarchyRequestError should be thrown if ' + type(node) +
-                ' is replaced by its inclusive ancestor' + parentCtor.name);
-            assert_equals(node.parent, parent1, type(node) + '.replace() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node], type(node) + '.replace() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node) + '.replace() should not change ' +
-                'parent attribute of replacement node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node) + '.replace() ' +
-                'should not change replacement node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if the node is replaced by its inclusive ancestor');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var parent1 = new parentCtor([node1]);
-            var parent2 = new parentCtor([parent1]);
-            var parent3 = new parentCtor([parent2]);
-            var parent4 = new parentCtor([parent3]);
-            var node2 = newAnimation(createDiv(test));
-            var parent5 = new parentCtor([node2]);
-
-            assert_throws('HierarchyRequestError', function() {
-                node1.replace(node2, parent3);
-            }, 'HierarchyRequestError should be thrown if ' + type(node1) +
-                ' is replaced by its inclusive ancestor' + parentCtor.name);
-            assert_equals(node1.parent, parent1, type(node1) + '.replace() should not change ' +
-                'parent attribute before throwing HierarchyRequestError');
-            assert_array_equals(parent1.children, [node1], type(node1) + '.replace() ' +
-                'should not change parent children before throwing HierarchyRequestError');
-            assert_equals(parent3.parent, parent4, type(node1) + '.replace() should not change ' +
-                'parent attribute of replacement node before throwing HierarchyRequestError');
-            assert_array_equals(parent4.children, [parent3], type(node1) + '.replace() ' +
-                'should not change replacement node parent children before throwing HierarchyRequestError');
-            assert_equals(node2.parent, parent5, type(node1) + '.replace() should not change ' +
-                'parent attribute of replacement node before throwing HierarchyRequestError');
-            assert_array_equals(parent5.children, [node2], type(node1) + '.replace() ' +
-                'should not change replacement node parent children before throwing HierarchyRequestError');
-        });
-    });
-}, 'HierarchyRequestError is thrown if node is replaced by its inclusive ancestor. ' +
-    'Test several arguments in replace() call');
-
-// Step 3. Let reference child be the next sibling of this animation node not in nodes.
-// Step 4. Remove this animation node from its parent animation group.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node) {
-            var parent = new parentCtor([node]);
-
-            node.replace();
-
-            assert_array_equals(parent.children, [], type(node) +
-                ' node should be removed from parent ' + parentCtor.name);
-            assert_equals(node.parent, null, type(node) +
-                ' node parent attribute should be updated');
-        });
-    });
-}, 'AnimationNode.replace() without arguments removes the node from the parent ' +
-    'animation group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-
-            node1.replace(node2);
-
-            assert_array_equals(parent.children, [node2], type(node1) +
-                ' node should be removed its parent group');
-            assert_equals(node1.parent, null, type(node1) +
-                ' node should be removed from its parent group');
-            assert_equals(node1.previousSibling, null, type(node1) +
-                ' node previousSibling attribute should be updated');
-            assert_equals(node1.nextSibling, null, type(node1) +
-                ' node nextSibling attribute should be updated');
-        });
-    });
-}, 'AnimationNode.replace() removes the node from its parent animation group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2, node3]);
-
-            node2.replace(node3);
-
-            assert_array_equals(parent.children, [node1,node3], type(node2) +
-                ' node should be removed from parent ' + parentCtor.name);
-            assert_equals(node2.parent, null, type(node2) +
-                ' node parent attribute should be updated');
-            assert_equals(node2.nextSibling, null, type(node2) +
-                ' node nextSibling attribute should be updated');
-            assert_equals(node2.previousSibling, null, type(node2) +
-                ' node previousSibling attribute should be updated');
-            assert_equals(node1.nextSibling, node3,
-                'Sibling node nextSibling attribute should be updated');
-            assert_equals(node3.previousSibling, node1,
-                'Sibling node previousSibling attribute should be updated');
-        });
-    });
-}, 'AnimationNode.replace(next sibling) removes the node from its parent ' +
-    'animation group');
-
-// Step 5. Insert nodes before reference child.
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-
-            node1.replace(node2);
-
-            assert_array_equals(parent.children, [node2], type(node1) +
-                ' node should be replaced');
-            assert_equals(node2.parent, parent,
-                'Replacement node should be assigned to a parent group');
-        });
-    });
-}, 'AnimationNode.replace() replaces node in the parent animation group');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node4) {
-            var node1 = newAnimation(createDiv(test));
-            var node2 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node4.replace(node1);
-
-            assert_array_equals(parent1.children, [node2],
-                'Replacement node should be removed from its previous position in the tree');
-            assert_array_equals(parent2.children, [node3, parent1, node1],
-                'Replacement node should be inserted into the new position');
-            assert_equals(node1.parent, parent2, 'Inserted node parent group should be assigned');
-            assert_equals(node1.previousSibling, parent1,
-                'Inserted node previousSibling attribute should be updated');
-            assert_equals(node1.nextSibling, null,
-                'Inserted node nextSibling attribute should be updated');
-
-            assert_equals(node4.parent, null, 'Node should be removed from its parent group');
-            assert_equals(node4.previousSibling, null,
-                'Replaced node previousSibling attribute should be updated');
-            assert_equals(node4.nextSibling, null,
-                'Replaced node nextSibling attribute should be updated');
-        });
-    });
-}, 'Test AnimationNode.replace() replaces given node. The previous position ' +
-    'of the replacement node is deeper in the tree than the current node');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent1 = new parentCtor([node1, node2]);
-            var parent2 = new parentCtor([node3, parent1, node4]);
-
-            node2.replace(node4);
-
-            assert_array_equals(parent1.children, [node1, node4],
-                'Replacement node should be inserted to the new position');
-            assert_array_equals(parent2.children, [node3, parent1],
-                'Replacement node should be removed from its previous position in the tree');
-            assert_equals(node4.parent, parent1, 'Inserted node parent group should be changed');
-            assert_equals(node4.previousSibling, node1,
-                'Inserted node previousSibling attribute should be updated');
-            assert_equals(node1.nextSibling, node4,
-                'Inserted node sibling nextSibling attribute should be updated');
-
-            assert_equals(node2.parent, null, 'Replaced node parent group should be changed');
-            assert_equals(node2.previousSibling, null,
-                'Replaced node previousSibling attribute should be updated');
-            assert_equals(node2.nextSibling, null, 'Replaced node nextSibling attribute ' +
-                'should be updated');
-        });
-    });
-}, 'Test AnimationNode.replace() replaces given node. The previous position ' +
-    'of the replacement node is shallower in the tree than current node, but is not an ancestor');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.replace(node3, node4);
-
-            assert_array_equals(parent.children, [node1, node3, node4], type(node2) + '.replace() ' +
-                'should replace the current node by ones passed in arguments');
-            assert_equals(node1.nextSibling, node3, 'nextSibling attribute should be updated');
-            assert_equals(node3.previousSibling, node1, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.nextSibling, node4, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.nextSibling, null, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.parent, parent, 'Parent group of the second inserted node ' +
-                'should be changed');
-            assert_equals(node2.parent, null, 'Replaced node parent group should be changed');
-            assert_equals(node2.previousSibling, null,
-                'Replaced node previousSibling attribute should be updated');
-            assert_equals(node2.nextSibling, null, 'Replaced node nextSibling attribute ' +
-                'should be updated');
-        });
-    });
-}, 'Test AnimationNode.replace() replaces given node. Test several arguments');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.replace(node3, node4, node3, node4);
-
-            assert_array_equals(parent.children, [node1, node3, node4], type(node2) + '.replace() ' +
-                'should replace the current node by ones passed in arguments');
-            assert_equals(node1.nextSibling, node3, 'nextSibling attribute should be updated');
-            assert_equals(node3.previousSibling, node1, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.nextSibling, node4, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node4.previousSibling, node3, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.nextSibling, null, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.parent, parent, 'Parent group of the second inserted node ' +
-                'should be changed');
-            assert_equals(node2.parent, null, 'Replaced node parent group should be changed');
-            assert_equals(node2.previousSibling, null,
-                'Replaced node previousSibling attribute should be updated');
-            assert_equals(node2.nextSibling, null, 'Replaced node nextSibling attribute ' +
-                'should be updated');
-        });
-    });
-}, 'Test AnimationNode.replace() replaces given node by several nodes, duplicate nodes are ignored');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node2) {
-            var node1 = newAnimation(createDiv(test));
-            var node3 = newAnimation(createDiv(test));
-            var node4 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1, node2]);
-
-            node2.replace(node3, node4, node3);
-
-            assert_array_equals(parent.children, [node1, node4, node3], type(node2) + '.replace() ' +
-                'should replace the current node by ones passed in arguments');
-            assert_equals(node1.nextSibling, node4, 'nextSibling attribute should be updated');
-            assert_equals(node4.previousSibling, node1, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.nextSibling, node3, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node4.parent, parent, 'Parent group of the inserted node should be changed');
-            assert_equals(node3.previousSibling, node4, 'Inserted node previousSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.nextSibling, null, 'Inserted node nextSibling attribute ' +
-                'should be updated');
-            assert_equals(node3.parent, parent, 'Parent group of the second inserted node ' +
-                'should be changed');
-            assert_equals(node2.parent, null, 'Replaced node parent group should be changed');
-            assert_equals(node2.previousSibling, null,
-                'Replaced node previousSibling attribute should be updated');
-            assert_equals(node2.nextSibling, null, 'Replaced node nextSibling attribute ' +
-                'should be updated');
-        });
-    });
-}, 'Test AnimationNode.replace() replaces given node by several nodes, check replacement order');
-
-test(function() {
-    var test = this;
-    var parents = [AnimationGroup, AnimationSequence];
-    parents.forEach(function(parentCtor) {
-        var nodes = [newAnimation(createDiv(test)), new AnimationGroup([]), new AnimationSequence([])];
-        nodes.forEach(function(node1) {
-            var node2 = newAnimation(createDiv(test));
-            var parent = new parentCtor([node1]);
-            var player = document.timeline.play(node2);
-
-            assert_equals(player.source, node2, 'The node should be associated with its player');
-            node1.replace(node2);
-            assert_equals(player.source, null, 'The node should be disassociated from its player');
-        });
-    });
-}, 'Test AnimationNode.replace() disassociates the inserted node from the player, ' +
-    'if node is directly associated with a player');
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/idlharness.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/idlharness.html
deleted file mode 100644
index d99a105..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/idlharness.html
+++ /dev/null
@@ -1,54 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>AnimationNode IDL tests</title>
-<link rel="author" title="Sergey G. Grekhov" href="mailto:sgrekhov@unipro.ru">
-<link rel="author" title="Aleksei Yu. Semenov" href="mailto:a.semenov@unipro.ru">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../../../../resources/WebIDLParser.js"></script>
-<script src="../../../../resources/idlharness.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></div>
-<script type="text/plain" id="untested-IDL">
-interface AnimationPlayer {
-};
-
-interface AnimationTiming {
-};
-
-interface ComputedTimingProperties {
-};
-
-interface AnimationGroup {
-};
-</script>
-<script type="text/plain" id="AnimationNode-IDL">
-interface AnimationNode {
-    // Timing
-    readonly attribute AnimationTiming          timing;
-    readonly attribute ComputedTimingProperties computedTiming;
-
-    // Timing hierarchy
-    readonly attribute AnimationGroup?          parent;
-    readonly attribute AnimationNode?           previousSibling;
-    readonly attribute AnimationNode?           nextSibling;
-    void before (AnimationNode... nodes);
-    void after (AnimationNode... nodes);
-    void replace (AnimationNode... nodes);
-    void remove ();
-};
-</script>
-<script>
-'use strict';
-
-var target = document.getElementById('target');
-var node = new Animation(target, [], 5);
-
-var idlArray = new IdlArray();
-idlArray.add_untested_idls(document.getElementById('untested-IDL').textContent);
-idlArray.add_idls(document.getElementById('AnimationNode-IDL').textContent);
-idlArray.add_objects( { AnimationNode: ['node'] } );
-idlArray.test();
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/document-timeline.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/document-timeline.html
deleted file mode 100644
index 3f57329d..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/document-timeline.html
+++ /dev/null
@@ -1,89 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Web Animations API: DocumentTimeline tests</title>
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<div id="log"></div>
-<iframe src="data:text/html;charset=utf-8," width="10" height="10" id="iframe"></iframe>
-<script>
-'use strict';
-
-test(function() {
-  assert_equals(document.timeline, document.timeline,
-    'document.timeline returns the same object every time');
-  var iframe = document.getElementById('iframe');
-  assert_not_equals(document.timeline, iframe.contentDocument.timeline,
-    'document.timeline returns a different object for each document');
-  assert_not_equals(iframe.contentDocument.timeline, null,
-    'document.timeline on an iframe is not null');
-},
-'document.timeline identity tests',
-{
-  help:   'http://dev.w3.org/fxtf/web-animations/#the-document-timeline',
-  assert: [ 'Each document has a timeline called the document timeline' ],
-  author: 'Brian Birtles'
-});
-
-async_test(function(t) {
-  assert_true(document.timeline.currentTime > 0,
-    'document.timeline.currentTime is positive');
-  // document.timeline.currentTime should be set even before document
-  // load fires. We expect this code to be run before document load and hence
-  // the above assertion is sufficient.
-  // If the following assertion fails, this test needs to be redesigned.
-  assert_true(document.readyState !== 'complete',
-    'Test is running prior to document load');
-
-  // Test that the document timeline's current time is measured from
-  // navigationStart.
-  //
-  // We can't just compare document.timeline.currentTime to
-  // window.performance.now() because currentTime is only updated on a sample
-  // so we use requestAnimationFrame instead.
-  window.requestAnimationFrame(t.step_func(function(rafTime) {
-    assert_equals(document.timeline.currentTime, rafTime,
-                  'document.timeline.currentTime matches' +
-                  ' requestAnimationFrame time');
-    t.done();
-  }));
-},
-'document.timeline.currentTime value tests',
-{
-  help: [
-    'http://dev.w3.org/fxtf/web-animations/#the-global-clock',
-    'http://dev.w3.org/fxtf/web-animations/#the-document-timeline'
-  ],
-  assert: [
-    'The global clock is a source of monotonically increasing time values',
-    'The time values of the document timeline are calculated as a fixed' +
-    ' offset from the global clock',
-    'the zero time corresponds to the navigationStart moment',
-    'the time value of each document timeline must be equal to the time ' +
-    'passed to animation frame request callbacks for that browsing context'
-  ],
-  author: 'Brian Birtles'
-});
-
-async_test(function(t) {
-  var valueAtStart = document.timeline.currentTime;
-  var timeAtStart = window.performance.now();
-  while (window.performance.now() - timeAtStart < 100) {
-    // Wait 100ms
-  }
-  assert_equals(document.timeline.currentTime, valueAtStart,
-    'document.timeline.currentTime does not change within a script block');
-  window.requestAnimationFrame(t.step_func(function() {
-    assert_true(document.timeline.currentTime > valueAtStart,
-      'document.timeline.currentTime increases between script blocks');
-    t.done();
-  }));
-},
-'document.timeline.currentTime liveness tests',
-{
-  help: 'http://dev.w3.org/fxtf/web-animations/#script-execution-and-live-updates-to-the-model',
-  assert: [ 'The value returned by the currentTime attribute of a' +
-            ' document timeline will not change within a script block' ],
-  author: 'Brian Birtles'
-});
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness-expected.txt
deleted file mode 100644
index 977c872..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Web Animations API: DocumentTimeline tests 
-PASS AnimationTimeline interface: existence and properties of interface object 
-PASS AnimationTimeline interface object length 
-PASS AnimationTimeline interface object name 
-FAIL AnimationTimeline interface: existence and properties of interface prototype object assert_equals: class string of AnimationTimeline.prototype expected "[object AnimationTimelinePrototype]" but got "[object AnimationTimeline]"
-PASS AnimationTimeline interface: existence and properties of interface prototype object's "constructor" property 
-FAIL AnimationTimeline interface: attribute currentTime assert_equals: setter must be undefined for readonly attributes expected (undefined) undefined but got (function) function "function () { [native code] }"
-FAIL DocumentTimeline interface: existence and properties of interface object assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL DocumentTimeline interface object length assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL DocumentTimeline interface object name assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL DocumentTimeline interface: existence and properties of interface prototype object assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL DocumentTimeline interface: existence and properties of interface prototype object's "constructor" property assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL DocumentTimeline must be primary interface of document.timeline assert_own_property: self does not have own property "DocumentTimeline" expected property "DocumentTimeline" missing
-FAIL Stringification of document.timeline assert_equals: class string of document.timeline expected "[object DocumentTimeline]" but got "[object AnimationTimeline]"
-PASS AnimationTimeline interface: document.timeline must inherit property "currentTime" with the proper type (0) 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness.html
deleted file mode 100644
index 7ca3530..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness.html
+++ /dev/null
@@ -1,29 +0,0 @@
-<!doctype html>
-<meta charset=utf-8>
-<title>Web Animations API: DocumentTimeline 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>
-<div id="log"></div>
-<script type="text/plain" id="DocumentTimeline-IDL">
-interface AnimationTimeline {
-  readonly attribute double? currentTime;
-};
-
-interface DocumentTimeline : AnimationTimeline {
-};
-</script>
-<script>
-'use strict';
-
-var idlArray;
-test(function() {
-  idlArray = new IdlArray();
-  idlArray.add_idls(
-    document.getElementById('DocumentTimeline-IDL').textContent);
-  idlArray.add_objects( { DocumentTimeline: ['document.timeline'] } );
-});
-idlArray.test();
-
-</script>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/constructor.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/constructor.html
deleted file mode 100644
index 2ea07710..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/constructor.html
+++ /dev/null
@@ -1,59 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Animation constructor tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#dom-animation-animation">
-<link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></div>
-<script>
-"use strict";
-
-var gTarget = document.getElementById("target");
-var gEffect = new KeyframeEffectReadOnly(gTarget, { opacity: [0, 1] });
-
-var gTestArguments = [
-  {
-    effect: null,
-    timeline: null,
-    description: "with null effect and null timeline"
-  },
-  {
-    effect: null,
-    timeline: document.timeline,
-    description: "with null effect and non-null timeline"
-  },
-  {
-    effect: gEffect,
-    timeline: null,
-    description: "with non-null effect and null timeline"
-  },
-  {
-    effect: gEffect,
-    timeline: document.timeline,
-    description: "with non-null effect and non-null timeline"
-  },
-];
-
-gTestArguments.forEach(function(args) {
-  test(function(t) {
-    var animation = new Animation(args.effect, args.timeline);
-
-    assert_not_equals(animation, null,
-                      "An animation sohuld be created");
-    assert_equals(animation.effect, args.effect,
-                  "Animation returns the same effect passed to " +
-                  "the Constructor");
-    assert_equals(animation.timeline, args.timeline,
-                  "Animation returns the same timeline passed to " +
-                  "the Constructor");
-    assert_equals(animation.playState, "idle",
-                  "Animation.playState should be initially 'idle'");
-  }, "Animation can be constructed " + args.description);
-});
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor-expected.txt
deleted file mode 100644
index ebc9f02..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor-expected.txt
+++ /dev/null
@@ -1,109 +0,0 @@
-This is a testharness.js-based test.
-FAIL a KeyframeEffectReadOnly can be constructed with no frames KeyframeEffectReadOnly is not defined
-FAIL easing values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in PropertyIndexedKeyframes KeyframeEffectReadOnly is not defined
-FAIL easing values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in Keyframe KeyframeEffectReadOnly is not defined
-FAIL easing values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in KeyframeTimingOptions KeyframeEffectReadOnly is not defined
-FAIL composite values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in PropertyIndexedKeyframes KeyframeEffectReadOnly is not defined
-FAIL composite values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in Keyframe KeyframeEffectReadOnly is not defined
-FAIL composite values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in KeyframeTimingOptions KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one shorthand property two value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one shorthand property two value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property (one shorthand and one of its longhand components) two value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property (one shorthand and one of its longhand components) two value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property two value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property two value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property PropertyIndexedKeyframes specification with different numbers of values KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property PropertyIndexedKeyframes specification with different numbers of values roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a PropertyIndexedKeyframes specification with an invalid value KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a PropertyIndexedKeyframes specification with an invalid value roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two value PropertyIndexedKeyframes specification that needs to stringify its values KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two value PropertyIndexedKeyframes specification that needs to stringify its values roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property one value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property one value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property one non-array value PropertyIndexedKeyframes specification KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property one non-array value PropertyIndexedKeyframes specification roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two value PropertyIndexedKeyframes specification where the first value is invalid KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two value PropertyIndexedKeyframes specification where the first value is invalid roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two value PropertyIndexedKeyframes specification where the second value is invalid KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two value PropertyIndexedKeyframes specification where the second value is invalid roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property PropertyIndexedKeyframes specification where one property is missing from the first Keyframe KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property PropertyIndexedKeyframes specification where one property is missing from the first Keyframe roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property PropertyIndexedKeyframes specification where one property is missing from the last Keyframe KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property PropertyIndexedKeyframes specification where one property is missing from the last Keyframe roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a PropertyIndexedKeyframes specification with repeated values at offset 0 with different easings KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a PropertyIndexedKeyframes specification with repeated values at offset 0 with different easings roundtrips KeyframeEffectReadOnly is not defined
-FAIL the KeyframeEffectReadOnly constructor reads Keyframe properties in the expected order KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two Keyframe sequence KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two Keyframe sequence roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property two Keyframe sequence KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property two Keyframe sequence roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one shorthand property two Keyframe sequence KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one shorthand property two Keyframe sequence roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property (a shorthand and one of its component longhands) two Keyframe sequence KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property (a shorthand and one of its component longhands) two Keyframe sequence roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence with duplicate values for a given interior offset KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence with duplicate values for a given interior offset roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence with duplicate values for offsets 0 and 1 KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence with duplicate values for offsets 0 and 1 roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property four Keyframe sequence KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property four Keyframe sequence roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property Keyframe sequence with some omitted offsets KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property Keyframe sequence with some omitted offsets roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a two property Keyframe sequence with some omitted offsets KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a two property Keyframe sequence with some omitted offsets roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property Keyframe sequence with all omitted offsets KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property Keyframe sequence with all omitted offsets roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence with different easing values, but the same easing value for a given offset KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence with different easing values, but the same easing value for a given offset roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence with different composite values, but the same composite value for a given offset KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence with different composite values, but the same composite value for a given offset roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a one property two Keyframe sequence that needs to stringify its values KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a one property two Keyframe sequence that needs to stringify its values roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence where shorthand precedes longhand KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence where shorthand precedes longhand roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence where longhand precedes shorthand KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence where longhand precedes shorthand roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence where lesser shorthand precedes greater shorthand KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence where lesser shorthand precedes greater shorthand roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly can be constructed with a Keyframe sequence where greater shorthand precedes lesser shorthand KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed with a Keyframe sequence where greater shorthand precedes lesser shorthand roundtrips KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed without any KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by an empty KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a normal KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a double value KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by +Infinity KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by an Infinity duration KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by an auto duration KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by an Infinity iterations KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a negative Infinity iterations KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a NaN iterations KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a negative iterations KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by an auto fill KeyframeEffectReadOnly is not defined
-FAIL a KeyframeEffectReadOnly constructed by a forwards fill KeyframeEffectReadOnly is not defined
-FAIL Invalid KeyframeEffectReadOnly option by -Infinity assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by NaN assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by a negative value assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by a negative Infinity duration assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by a NaN duration assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by a negative duration assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-FAIL Invalid KeyframeEffectReadOnly option by a string duration assert_throws: function "function () {
-      new KeyframeEffectReadOnly(target,
-  ..." threw object "ReferenceError: KeyframeEffectReadOnly is not defined" ("ReferenceError") expected object "[object Object]" ("TypeError")
-PASS KeyframeEffect constructor creates an AnimationEffectTiming timing object 
-PASS KeyframeEffect constructor propagates exceptions generated by accessing the options object 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor.html
deleted file mode 100644
index 142ec337..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor.html
+++ /dev/null
@@ -1,601 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>KeyframeEffectReadOnly constructor tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#the-keyframeeffect-interfaces">
-<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></div>
-<style>
-#target {
-  border-style: solid;  /* so border-*-width values don't compute to 0 */
-}
-</style>
-<script>
-"use strict";
-
-var target = document.getElementById("target");
-
-function assert_frames_equal(a, b, name) {
-  assert_equals(Object.keys(a).sort().toString(),
-                Object.keys(b).sort().toString(),
-                "properties on " + name);
-  for (var p in a) {
-    assert_equals(a[p], b[p], "value for '" + p + "' on " + name);
-  }
-}
-
-function assert_frame_lists_equal(a, b) {
-  assert_equals(a.length, b.length, "number of frames");
-  for (var i = 0; i < Math.min(a.length, b.length); i++) {
-    assert_frames_equal(a[i], b[i], "ComputedKeyframe #" + i);
-  }
-}
-
-var gEmptyKeyframeListTests = [
-  [],
-  [{}],
-  [{ easing: "ease-in" }],
-  [{ unknown: "unknown" }, { unknown: "unknown" }],
-  [{ color: "invalid" }, { color: "invalid" }],
-  { easing: "ease-in" },
-  { unknown: "unknown" },
-  { unknown: [] },
-  { unknown: ["unknown"] },
-  { unknown: ["unknown", "unknown"] },
-  { animationName: ["none", "abc"] },
-  { color: [] },
-  null,
-  undefined,
-];
-
-test(function(t) {
-  gEmptyKeyframeListTests.forEach(function(frames) {
-    assert_equals(new KeyframeEffectReadOnly(target, frames).getFrames().length,
-                  0, "number of frames for " + JSON.stringify(frames));
-  });
-}, "a KeyframeEffectReadOnly can be constructed with no frames");
-
-// [specified easing value, expected easing value]
-var gEasingValueTests = [
-  ["unrecognised", "linear"],
-  ["linear", "linear"],
-  ["ease-in-out", "ease-in-out"],
-  ["initial", "linear"],
-  ["inherit", "linear"],
-  ["var(--x)", "linear"],
-  ["ease-in-out, ease-out", "linear"],
-  ["Ease\\2d in-out", "ease-in-out"],
-  ["ease /**/", "ease"],
-];
-
-test(function(t) {
-  gEasingValueTests.forEach(function(subtest) {
-    var easing = subtest[0];
-    var expected = subtest[1];
-    var effect = new KeyframeEffectReadOnly(target, {
-      left: ["10px", "20px"],
-      easing: easing
-    });
-    assert_equals(effect.getFrames()[0].easing, expected,
-                  "resulting easing for '" + easing + "'");
-  });
-}, "easing values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in PropertyIndexedKeyframes");
-
-test(function(t) {
-  gEasingValueTests.forEach(function(subtest) {
-    var easing = subtest[0];
-    var expected = subtest[1];
-    var effect = new KeyframeEffectReadOnly(target, [
-      { offset: 0, left: "10px", easing: easing },
-      { offset: 1, left: "20px" }
-    ]);
-    assert_equals(effect.getFrames()[0].easing, expected,
-                  "resulting easing for '" + easing + "'");
-  });
-}, "easing values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in Keyframe");
-
-test(function(t) {
-  gEasingValueTests.forEach(function(subtest) {
-    var easing = subtest[0];
-    var expected = subtest[1];
-    var effect = new KeyframeEffectReadOnly(target, {
-      left: ["10px", "20px"]
-    }, { easing: easing });
-    assert_equals(effect.timing.easing, expected,
-                  "resulting easing for '" + easing + "'");
-  });
-}, "easing values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
-
-var gGoodCompositeValueTests = [
-  "replace", "add", "accumulate"
-];
-
-var gBadCompositeValueTests = [
-  "unrecognised", "replace ", "Replace"
-];
-
-test(function(t) {
-  gGoodCompositeValueTests.forEach(function(composite) {
-    var effect = new KeyframeEffectReadOnly(target, {
-      left: ["10px", "20px"],
-      composite: composite
-    });
-    assert_equals(effect.getFrames()[0].composite, composite,
-                  "resulting composite for '" + composite + "'");
-  });
-  gBadCompositeValueTests.forEach(function(composite) {
-    assert_throws(new TypeError, function() {
-                    new KeyframeEffectReadOnly(target, {
-                      left: ["10px", "20px"],
-                      composite: composite
-                    });
-                  });
-  });
-}, "composite values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in PropertyIndexedKeyframes");
-
-test(function(t) {
-  gGoodCompositeValueTests.forEach(function(composite) {
-    var effect = new KeyframeEffectReadOnly(target, [
-      { offset: 0, left: "10px", composite: composite },
-      { offset: 1, left: "20px" }
-    ]);
-    assert_equals(effect.getFrames()[0].composite, composite,
-                  "resulting composite for '" + composite + "'");
-  });
-  gBadCompositeValueTests.forEach(function(composite) {
-    assert_throws(new TypeError, function() {
-                    new KeyframeEffectReadOnly(target, [
-                      { offset: 0, left: "10px", composite: composite },
-                      { offset: 1, left: "20px" }
-                    ]);
-                  });
-  });
-}, "composite values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in Keyframe");
-
-test(function(t) {
-  gGoodCompositeValueTests.forEach(function(composite) {
-    var effect = new KeyframeEffectReadOnly(target, {
-      left: ["10px", "20px"]
-    }, { composite: composite });
-    assert_equals(effect.getFrames()[0].composite, composite,
-                  "resulting composite for '" + composite + "'");
-  });
-  gBadCompositeValueTests.forEach(function(composite) {
-    assert_throws(new TypeError, function() {
-                                   new KeyframeEffectReadOnly(target, {
-                                     left: ["10px", "20px"]
-                                   }, { composite: composite });
-                                 });
-  });
-}, "composite values are parsed correctly when passed to the " +
-   "KeyframeEffectReadOnly constructor in KeyframeTimingOptions");
-
-var gPropertyIndexedKeyframesTests = [
-  { desc:   "a one property two value PropertyIndexedKeyframes specification",
-    input:  { left: ["10px", "20px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "20px" }] },
-  { desc:   "a one shorthand property two value PropertyIndexedKeyframes specification",
-    input:  { margin: ["10px", "10px 20px 30px 40px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginTop: "10px", marginRight: "10px", marginBottom: "10px", marginLeft: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginTop: "10px", marginRight: "20px", marginBottom: "30px", marginLeft: "40px" }] },
-  { desc:   "a two property (one shorthand and one of its longhand components) two value PropertyIndexedKeyframes specification",
-    input:  { marginTop: ["50px", "60px"],
-              margin: ["10px", "10px 20px 30px 40px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginTop: "50px", marginRight: "10px", marginBottom: "10px", marginLeft: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginTop: "60px", marginRight: "20px", marginBottom: "30px", marginLeft: "40px" }] },
-  { desc:   "a two property two value PropertyIndexedKeyframes specification",
-    input:  { left: ["10px", "20px"],
-              top: ["30px", "40px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px", top: "30px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "20px", top: "40px" }] },
-  { desc:   "a two property PropertyIndexedKeyframes specification with different numbers of values",
-    input:  { left: ["10px", "20px", "30px"],
-              top: ["40px", "50px"] },
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear", composite: "replace", left: "10px", top: "40px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "replace", left: "20px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "linear", composite: "replace", left: "30px", top: "50px" }] },
-  { desc:   "a PropertyIndexedKeyframes specification with an invalid value",
-    input:  { left: ["10px", "20px", "30px", "40px", "50px"],
-              top:  ["15px", "25px", "invalid", "45px", "55px"] },
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", composite: "replace", left: "10px", top: "15px" },
-             { offset: 0.25, computedOffset: 0.25, easing: "linear", composite: "replace", left: "20px", top: "25px" },
-             { offset: 0.50, computedOffset: 0.50, easing: "linear", composite: "replace", left: "30px" },
-             { offset: 0.75, computedOffset: 0.75, easing: "linear", composite: "replace", left: "40px", top: "45px" },
-             { offset: 1.00, computedOffset: 1.00, easing: "linear", composite: "replace", left: "50px", top: "55px" }] },
-  { desc:   "a one property two value PropertyIndexedKeyframes specification that needs to stringify its values",
-    input:  { opacity: [0, 1] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", opacity: "0" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", opacity: "1" }] },
-  { desc:   "a one property one value PropertyIndexedKeyframes specification",
-    input:  { left: ["10px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "10px" }] },
-  { desc:   "a one property one non-array value PropertyIndexedKeyframes specification",
-    input:  { left: "10px" },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "10px" }] },
-  { desc:   "a one property two value PropertyIndexedKeyframes specification where the first value is invalid",
-    input:  { left: ["invalid", "10px"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "10px" }] },
-  { desc:   "a one property two value PropertyIndexedKeyframes specification where the second value is invalid",
-    input:  { left: ["10px", "invalid"] },
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace" }] },
-  { desc:   "a two property PropertyIndexedKeyframes specification where one property is missing from the first Keyframe",
-    input:  [{ offset: 0, left: "10px" },
-             { offset: 1, left: "20px", top: "30px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "20px", top: "30px" }] },
-  { desc:   "a two property PropertyIndexedKeyframes specification where one property is missing from the last Keyframe",
-    input:  [{ offset: 0, left: "10px", top: "20px" },
-             { offset: 1, left: "30px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" , top: "20px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "30px" }] },
-  { desc:   "a PropertyIndexedKeyframes specification with repeated values at offset 0 with different easings",
-    input:  [{ offset: 0.0, left: "100px", easing: "ease" },
-             { offset: 0.0, left: "200px", easing: "ease" },
-             { offset: 0.5, left: "300px", easing: "linear" },
-             { offset: 1.0, left: "400px", easing: "ease-out" },
-             { offset: 1.0, left: "500px", easing: "step-end" }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",     composite: "replace", left: "100px" },
-             { offset: 0.0, computedOffset: 0.0, easing: "ease",     composite: "replace", left: "200px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear",   composite: "replace", left: "300px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "ease-out", composite: "replace", left: "400px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "linear",   composite: "replace", left: "500px" }] },
-];
-
-gPropertyIndexedKeyframesTests.forEach(function(subtest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target, subtest.input);
-    assert_frame_lists_equal(effect.getFrames(), subtest.output);
-  }, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
-
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target, subtest.input);
-    var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames());
-    assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames());
-  }, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
-     " roundtrips");
-});
-
-test(function(t) {
-  var expectedOrder = ["composite", "easing", "offset", "left", "marginLeft"];
-  var actualOrder = [];
-  var kf1 = {};
-  var kf2 = { marginLeft: "10px", left: "20px", offset: 1 };
-  [{ p: "marginLeft", v: "10px" },
-   { p: "left",       v: "20px" },
-   { p: "offset",     v: "0" },
-   { p: "easing",     v: "linear" },
-   { p: "composite",  v: null }].forEach(function(e) {
-    Object.defineProperty(kf1, e.p, {
-      enumerable: true,
-      get: function() { actualOrder.push(e.p); return e.v; }
-    });
-  });
-  new KeyframeEffectReadOnly(target, [kf1, kf2]);
-  assert_array_equals(actualOrder, expectedOrder, "property access order");
-}, "the KeyframeEffectReadOnly constructor reads Keyframe properties in the " +
-   "expected order");
-
-var gKeyframeSequenceTests = [
-  { desc:   "a one property two Keyframe sequence",
-    input:  [{ offset: 0, left: "10px" },
-             { offset: 1, left: "20px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "20px" }] },
-  { desc:   "a two property two Keyframe sequence",
-    input:  [{ offset: 0, left: "10px", top: "30px" },
-             { offset: 1, left: "20px", top: "40px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px", top: "30px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "20px", top: "40px" }] },
-  { desc:   "a one shorthand property two Keyframe sequence",
-    input:  [{ offset: 0, margin: "10px" },
-             { offset: 1, margin: "20px 30px 40px 50px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginTop: "10px", marginRight: "10px", marginBottom: "10px", marginLeft: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginTop: "20px", marginRight: "30px", marginBottom: "40px", marginLeft: "50px" }] },
-  { desc:   "a two property (a shorthand and one of its component longhands) two Keyframe sequence",
-    input:  [{ offset: 0, margin: "10px", marginTop: "20px" },
-             { offset: 1, marginTop: "70px", margin: "30px 40px 50px 60px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginTop: "20px", marginRight: "10px", marginBottom: "10px", marginLeft: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginTop: "70px", marginRight: "40px", marginBottom: "50px", marginLeft: "60px" }] },
-  { desc:   "a Keyframe sequence with duplicate values for a given interior offset",
-    input:  [{ offset: 0.0, left: "10px" },
-             { offset: 0.5, left: "20px" },
-             { offset: 0.5, left: "30px" },
-             { offset: 0.5, left: "40px" },
-             { offset: 1.0, left: "50px" }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "replace", left: "20px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "replace", left: "40px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "linear", composite: "replace", left: "50px" }] },
-  { desc:   "a Keyframe sequence with duplicate values for offsets 0 and 1",
-    input:  [{ offset: 0, left: "10px" },
-             { offset: 0, left: "20px" },
-             { offset: 0, left: "30px" },
-             { offset: 1, left: "40px" },
-             { offset: 1, left: "50px" },
-             { offset: 1, left: "60px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "30px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "40px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "60px" }] },
-  { desc:   "a two property four Keyframe sequence",
-    input:  [{ offset: 0, left: "10px" },
-             { offset: 0, top: "20px" },
-             { offset: 1, top: "30px" },
-             { offset: 1, left: "40px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", left: "10px", top: "20px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", left: "40px", top: "30px" }] },
-  { desc:   "a one property Keyframe sequence with some omitted offsets",
-    input:  [{ offset: 0.00, left: "10px" },
-             { offset: 0.25, left: "20px" },
-             { left: "30px" },
-             { left: "40px" },
-             { offset: 1.00, left: "50px" }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 0.25, computedOffset: 0.25, easing: "linear", composite: "replace", left: "20px" },
-             { offset: 0.50, computedOffset: 0.50, easing: "linear", composite: "replace", left: "30px" },
-             { offset: 0.75, computedOffset: 0.75, easing: "linear", composite: "replace", left: "40px" },
-             { offset: 1.00, computedOffset: 1.00, easing: "linear", composite: "replace", left: "50px" }] },
-  { desc:   "a two property Keyframe sequence with some omitted offsets",
-    input:  [{ offset: 0.00, left: "10px", top: "20px" },
-             { offset: 0.25, left: "30px" },
-             { left: "40px" },
-             { left: "50px", top: "60px" },
-             { offset: 1.00, left: "70px", top: "80px" }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", composite: "replace", left: "10px", top: "20px" },
-             { offset: 0.25, computedOffset: 0.25, easing: "linear", composite: "replace", left: "30px" },
-             { offset: 0.50, computedOffset: 0.50, easing: "linear", composite: "replace", left: "40px" },
-             { offset: 0.75, computedOffset: 0.75, easing: "linear", composite: "replace", left: "50px", top: "60px" },
-             { offset: 1.00, computedOffset: 1.00, easing: "linear", composite: "replace", left: "70px", top: "80px" }] },
-  { desc:   "a one property Keyframe sequence with all omitted offsets",
-    input:  [{ left: "10px" },
-             { left: "20px" },
-             { left: "30px" },
-             { left: "40px" },
-             { left: "50px" }],
-    output: [{ offset: 0.00, computedOffset: 0.00, easing: "linear", composite: "replace", left: "10px" },
-             { offset: 0.25, computedOffset: 0.25, easing: "linear", composite: "replace", left: "20px" },
-             { offset: 0.50, computedOffset: 0.50, easing: "linear", composite: "replace", left: "30px" },
-             { offset: 0.75, computedOffset: 0.75, easing: "linear", composite: "replace", left: "40px" },
-             { offset: 1.00, computedOffset: 1.00, easing: "linear", composite: "replace", left: "50px" }] },
-  { desc:   "a Keyframe sequence with different easing values, but the same easing value for a given offset",
-    input:  [{ offset: 0.0, easing: "ease",     left: "10px"},
-             { offset: 0.0, easing: "ease",     top: "20px"},
-             { offset: 0.5, easing: "linear",   left: "30px" },
-             { offset: 0.5, easing: "linear",   top: "40px" },
-             { offset: 1.0, easing: "step-end", left: "50px" },
-             { offset: 1.0, easing: "step-end", top: "60px" }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: "ease",         composite: "replace", left: "10px", top: "20px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "replace", left: "30px", top: "40px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "linear", composite: "replace", left: "50px", top: "60px" }] },
-  { desc:   "a Keyframe sequence with different composite values, but the same composite value for a given offset",
-    input:  [{ offset: 0.0, composite: "replace", left: "10px" },
-             { offset: 0.0, composite: "replace", top: "20px" },
-             { offset: 0.5, composite: "add",     left: "30px" },
-             { offset: 0.5, composite: "add",     top: "40px" },
-             { offset: 1.0, composite: "replace", left: "50px" },
-             { offset: 1.0, composite: "replace", top: "60px" }],
-    output: [{ offset: 0.0, computedOffset: 0.0, easing: "linear", composite: "replace", left: "10px", top: "20px" },
-             { offset: 0.5, computedOffset: 0.5, easing: "linear", composite: "add",     left: "30px", top: "40px" },
-             { offset: 1.0, computedOffset: 1.0, easing: "linear", composite: "replace", left: "50px", top: "60px" }] },
-  { desc:   "a one property two Keyframe sequence that needs to stringify its values",
-    input:  [{ offset: 0, opacity: 0 },
-             { offset: 1, opacity: 1 }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", opacity: "0" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", opacity: "1" }] },
-  { desc:   "a Keyframe sequence where shorthand precedes longhand",
-    input:  [{ offset: 0, margin: "10px", marginRight: "20px" },
-             { offset: 1, margin: "30px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginBottom: "10px", marginLeft: "10px", marginRight: "20px", marginTop: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginBottom: "30px", marginLeft: "30px", marginRight: "30px", marginTop: "30px" }] },
-  { desc:   "a Keyframe sequence where longhand precedes shorthand",
-    input:  [{ offset: 0, marginRight: "20px", margin: "10px" },
-             { offset: 1, margin: "30px" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace", marginBottom: "10px", marginLeft: "10px", marginRight: "20px", marginTop: "10px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace", marginBottom: "30px", marginLeft: "30px", marginRight: "30px", marginTop: "30px" }] },
-  { desc:   "a Keyframe sequence where lesser shorthand precedes greater shorthand",
-    input:  [{ offset: 0, borderLeft: "1px solid rgb(1, 2, 3)", border: "2px dotted rgb(4, 5, 6)" },
-             { offset: 1, border: "3px dashed rgb(7, 8, 9)" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace",
-                 borderBottomColor: "rgb(4, 5, 6)", borderBottomWidth: "2px",
-                 borderLeftColor:   "rgb(1, 2, 3)", borderLeftWidth:   "1px",
-                 borderRightColor:  "rgb(4, 5, 6)", borderRightWidth:  "2px",
-                 borderTopColor:    "rgb(4, 5, 6)", borderTopWidth:    "2px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace",
-                 borderBottomColor: "rgb(7, 8, 9)", borderBottomWidth: "3px",
-                 borderLeftColor:   "rgb(7, 8, 9)", borderLeftWidth:   "3px",
-                 borderRightColor:  "rgb(7, 8, 9)", borderRightWidth:  "3px",
-                 borderTopColor:    "rgb(7, 8, 9)", borderTopWidth:    "3px" }] },
-  { desc:   "a Keyframe sequence where greater shorthand precedes lesser shorthand",
-    input:  [{ offset: 0, border: "2px dotted rgb(4, 5, 6)", borderLeft: "1px solid rgb(1, 2, 3)" },
-             { offset: 1, border: "3px dashed rgb(7, 8, 9)" }],
-    output: [{ offset: 0, computedOffset: 0, easing: "linear", composite: "replace",
-                 borderBottomColor: "rgb(4, 5, 6)", borderBottomWidth: "2px",
-                 borderLeftColor:   "rgb(1, 2, 3)", borderLeftWidth:   "1px",
-                 borderRightColor:  "rgb(4, 5, 6)", borderRightWidth:  "2px",
-                 borderTopColor:    "rgb(4, 5, 6)", borderTopWidth:    "2px" },
-             { offset: 1, computedOffset: 1, easing: "linear", composite: "replace",
-                 borderBottomColor: "rgb(7, 8, 9)", borderBottomWidth: "3px",
-                 borderLeftColor:   "rgb(7, 8, 9)", borderLeftWidth:   "3px",
-                 borderRightColor:  "rgb(7, 8, 9)", borderRightWidth:  "3px",
-                 borderTopColor:    "rgb(7, 8, 9)", borderTopWidth:    "3px" }] },
-];
-
-gKeyframeSequenceTests.forEach(function(subtest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target, subtest.input);
-    assert_frame_lists_equal(effect.getFrames(), subtest.output);
-  }, "a KeyframeEffectReadOnly can be constructed with " + subtest.desc);
-
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target, subtest.input);
-    var secondEffect = new KeyframeEffectReadOnly(target, effect.getFrames());
-    assert_frame_lists_equal(secondEffect.getFrames(), effect.getFrames());
-  }, "a KeyframeEffectReadOnly constructed with " + subtest.desc +
-     " roundtrips");
-});
-
-
-test(function(t) {
-  var effect = new KeyframeEffectReadOnly(target,
-                                          {left: ["10px", "20px"]});
-
-  var timing = effect.timing;
-  assert_equals(timing.delay, 0, "default delay");
-  assert_equals(timing.endDelay, 0, "default endDelay");
-  assert_equals(timing.fill, "auto", "default fill");
-  assert_equals(timing.iterations, 1.0, "default iterations");
-  assert_equals(timing.iterationStart, 0.0, "default iterationStart");
-  assert_equals(timing.duration, "auto", "default duration");
-  assert_equals(timing.direction, "normal", "default direction");
-  assert_equals(timing.easing, "linear", "default easing");
-
-  assert_equals(effect.composite, "replace", "default composite");
-  assert_equals(effect.iterationComposite, "replace",
-                "default iterationComposite");
-  assert_equals(effect.spacing, "distribute",
-                "default spacing");
-}, "a KeyframeEffectReadOnly constructed without any " +
-   "KeyframeEffectOptions object");
-
-var gKeyframeEffectOptionTests = [
-  { desc:     "an empty KeyframeEffectOptions object",
-    input:    { },
-    expected: { } },
-  { desc:     "a normal KeyframeEffectOptions object",
-    input:    { delay: 1000,
-                fill: "auto",
-                iterations: 5.5,
-                duration: "auto",
-                direction: "alternate" },
-    expected: { delay: 1000,
-                fill: "auto",
-                iterations: 5.5,
-                duration: "auto",
-                direction: "alternate" } },
-  { desc:     "a double value",
-    input:    3000,
-    expected: { duration: 3000 } },
-  { desc:     "+Infinity",
-    input:    Infinity,
-    expected: { duration: Infinity } },
-  { desc:     "an Infinity duration",
-    input:    { duration: Infinity },
-    expected: { duration: Infinity } },
-  { desc:     "an auto duration",
-    input:    { duration: "auto" },
-    expected: { duration: "auto" } },
-  { desc:     "an Infinity iterations",
-    input:    { iterations: Infinity },
-    expected: { iterations: Infinity } },
-  { desc:     "a negative Infinity iterations",
-    input:    { iterations: -Infinity },
-    expected: { iterations: -Infinity } },
-  { desc:     "a NaN iterations",
-    input:    { iterations: NaN },
-    expected: { iterations: NaN } },
-  { desc:     "a negative iterations",
-    input:    { iterations: -1 },
-    expected: { iterations: -1 } },
-  { desc:     "an auto fill",
-    input:    { fill: "auto" },
-    expected: { fill: "auto" } },
-  { desc:     "a forwards fill",
-    input:    { fill: "forwards" },
-    expected: { fill: "forwards" } }
-];
-
-gKeyframeEffectOptionTests.forEach(function(stest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target,
-                                            {left: ["10px", "20px"]},
-                                            stest.input);
-
-    // Helper function to provide default expected values when the test does
-    // not supply them.
-    var expected = function(field, defaultValue) {
-      return field in stest.expected ? stest.expected[field] : defaultValue;
-    };
-
-    var timing = effect.timing;
-    assert_equals(timing.delay, expected("delay", 0),
-                  "timing delay");
-    assert_equals(timing.fill, expected("fill", "auto"),
-                  "timing fill");
-    assert_equals(timing.iterations, expected("iterations", 1),
-                  "timing iterations");
-    assert_equals(timing.duration, expected("duration", "auto"),
-                  "timing duration");
-    assert_equals(timing.direction, expected("direction", "normal"),
-                  "timing direction");
-
-  }, "a KeyframeEffectReadOnly constructed by " + stest.desc);
-});
-
-var gInvalidKeyframeEffectOptionTests = [
-  { desc:     "-Infinity",
-    input:    -Infinity,
-    expected: { name: "TypeError" } },
-  { desc:     "NaN",
-    input:    NaN,
-    expected: { name: "TypeError" } },
-  { desc:     "a negative value",
-    input:    -1,
-    expected: { name: "TypeError" } },
-  { desc:     "a negative Infinity duration",
-    input:    { duration: -Infinity },
-    expected: { name: "TypeError" } },
-  { desc:     "a NaN duration",
-    input:    { duration: NaN },
-    expected: { name: "TypeError" } },
-  { desc:     "a negative duration",
-    input:    { duration: -1 },
-    expected: { name: "TypeError" } },
-  { desc:     "a string duration",
-    input:    { duration: "merrychristmas" },
-    expected: { name: "TypeError" } }
-];
-
-gInvalidKeyframeEffectOptionTests.forEach(function(stest) {
-  test(function(t) {
-    assert_throws(stest.expected, function() {
-      new KeyframeEffectReadOnly(target,
-                                 {left: ["10px", "20px"]},
-                                 stest.input);
-    });
-  }, "Invalid KeyframeEffectReadOnly option by " + stest.desc);
-});
-
-test(function(t) {
-  var effect = new KeyframeEffect(target,
-                                  { left: ["10px", "20px"] });
-
-  assert_class_string(effect, "KeyframeEffect");
-  assert_class_string(effect.timing, "AnimationEffectTiming");
-}, "KeyframeEffect constructor creates an AnimationEffectTiming timing object");
-
-test(function(t) {
-  var test_error = { name: "test" };
-
-  assert_throws(test_error, function() {
-    new KeyframeEffect(target, { get left() { throw test_error }})
-  });
-}, "KeyframeEffect constructor propagates exceptions generated by accessing"
-   + " the options object");
-
-done();
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing-expected.txt
deleted file mode 100644
index 2f6daba..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing-expected.txt
+++ /dev/null
@@ -1,24 +0,0 @@
-This is a testharness.js-based test.
-FAIL steps(start) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL steps(end) function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL linear function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL ease function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL ease-in function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL ease-in-out function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL ease-out function Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL easing function which produces values greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL easing function which produces negative values Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing produces values greater than 1 with keyframe easing cubic-bezier(0, 0, 0, 0) Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing produces values greater than 1 with keyframe easing cubic-bezier(1, 1, 1, 1) Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing produces negative values 1 with keyframe easing cubic-bezier(0, 0, 0, 0) Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing produces negative values 1 with keyframe easing cubic-bezier(1, 1, 1, 1) Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-PASS effect easing produces values greater than 1 with step-start keyframe 
-PASS effect easing produces values greater than 1 with step-end keyframe 
-PASS effect easing produces negative values with step-start keyframe 
-PASS effect easing produces negative values with step-end keyframe 
-FAIL effect easing produces values greater than 1 with keyframe easing producing values greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing which produces values greater than 1 and the tangent on the upper boundary is infinity with keyframe easing producing values greater than 1 Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing produces negative values with keyframe easing producing negative values Failed to execute 'getComputedStyle' on 'Window': parameter 1 is not of type 'Element'.
-FAIL effect easing which produces negative values and the tangent on the lower boundary is infinity with keyframe easing producing negative values 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/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing.html
deleted file mode 100644
index 9e518efb..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing.html
+++ /dev/null
@@ -1,438 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Effect-level easing tests</title>
-<link rel="help" href="http://w3c.github.io/web-animations/#calculating-the-transformed-time">
-<link rel="author" title="Hiroyuki Ikezoe" href="mailto:hiikezoe@mozilla-japan.org">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></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');
-}
-
-var gEffectEasingTests = [
-  {
-    desc: 'steps(start) function',
-    easing: 'steps(2, start)',
-    easingFunction: stepStart(2)
-  },
-  {
-    desc: 'steps(end) function',
-    easing: 'steps(2, end)',
-    easingFunction: stepEnd(2)
-  },
-  {
-    desc: 'linear function',
-    easing: 'linear', // cubic-bezier(0, 0, 1.0, 1.0)
-    easingFunction: cubicBezier(0, 0, 1.0, 1.0)
-  },
-  {
-    desc: 'ease function',
-    easing: 'ease', // cubic-bezier(0.25, 0.1, 0.25, 1.0)
-    easingFunction: cubicBezier(0.25, 0.1, 0.25, 1.0)
-  },
-  {
-    desc: 'ease-in function',
-    easing: 'ease-in', // cubic-bezier(0.42, 0, 1.0, 1.0)
-    easingFunction: cubicBezier(0.42, 0, 1.0, 1.0)
-  },
-  {
-    desc: 'ease-in-out function',
-    easing: 'ease-in-out', // cubic-bezier(0.42, 0, 0.58, 1.0)
-    easingFunction: cubicBezier(0.42, 0, 0.58, 1.0)
-  },
-  {
-    desc: 'ease-out function',
-    easing: 'ease-out', // cubic-bezier(0, 0, 0.58, 1.0)
-    easingFunction: cubicBezier(0, 0, 0.58, 1.0)
-  },
-  {
-    desc: 'easing function which produces values greater than 1',
-    easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
-    easingFunction: cubicBezier(0, 1.5, 1, 1.5)
-  },
-  {
-    desc: 'easing function which produces negative values',
-    easing: 'cubic-bezier(0, -0.5 ,1, -0.5)',
-    easingFunction: cubicBezier(0, -0.5, 1, -0.5)
-  },
-];
-
-gEffectEasingTests.forEach(function(options) {
-  test(function(t) {
-    var target = createDiv(t);
-    target.style.position = 'absolute';
-    var anim = target.animate([ { left: '0px' }, { left: '100px' } ],
-                              { duration: 1000,
-                                fill: 'forwards',
-                                easing: options.easing });
-    var easing = options.easingFunction;
-
-    anim.pause();
-
-    assert_style_left_at(anim, 0, easing);
-    assert_style_left_at(anim, 250, easing);
-    assert_style_left_at(anim, 500, easing);
-    assert_style_left_at(anim, 750, easing);
-    assert_style_left_at(anim, 1000, easing);
-  }, options.desc);
-});
-
-var gEffectEasingTestsWithKeyframeEasing = [
-  {
-    desc: 'effect easing produces values greater than 1 with keyframe ' +
-          'easing cubic-bezier(0, 0, 0, 0)',
-    easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
-    keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
-    easingFunction: cubicBezier(0, 1.5, 1, 1.5)
-  },
-  {
-    desc: 'effect easing produces values greater than 1 with keyframe ' +
-          'easing cubic-bezier(1, 1, 1, 1)',
-    easing: 'cubic-bezier(0, 1.5, 1, 1.5)',
-    keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
-    easingFunction: cubicBezier(0, 1.5, 1, 1.5)
-  },
-  {
-    desc: 'effect easing produces negative values 1 with keyframe ' +
-          'easing cubic-bezier(0, 0, 0, 0)',
-    easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
-    keyframeEasing: 'cubic-bezier(0, 0, 0, 0)', // linear
-    easingFunction: cubicBezier(0, -0.5, 1, -0.5)
-  },
-  {
-    desc: 'effect easing produces negative values 1 with keyframe ' +
-          'easing cubic-bezier(1, 1, 1, 1)',
-    easing: 'cubic-bezier(0, -0.5, 1, -0.5)',
-    keyframeEasing: 'cubic-bezier(1, 1, 1, 1)', // linear
-    easingFunction: cubicBezier(0, -0.5, 1, -0.5)
-  },
-];
-
-gEffectEasingTestsWithKeyframeEasing.forEach(function(options) {
-  test(function(t) {
-    var target = createDiv(t);
-    target.style.position = 'absolute';
-    var anim = target.animate(
-      [ { left: '0px', easing: options.keyframeEasing },
-        { left: '100px' } ],
-        { duration: 1000,
-          fill: 'forwards',
-          easing: options.easing });
-    var easing = options.easingFunction;
-
-    anim.pause();
-
-    assert_style_left_at(anim, 0, easing);
-    assert_style_left_at(anim, 250, easing);
-    assert_style_left_at(anim, 500, easing);
-    assert_style_left_at(anim, 750, easing);
-    assert_style_left_at(anim, 1000, easing);
-  }, options.desc);
-});
-
-// Other test cases that effect easing produces values outside of [0,1].
-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)' });
-  anim.pause();
-
-  // The bezier function produces values greater than 1 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, '100px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'effect easing produces values greater than 1 with step-start keyframe');
-
-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)' });
-  anim.pause();
-
-  // The bezier function produces values greater than 1 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');
-}, 'effect easing produces values greater than 1 with step-end keyframe');
-
-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)' });
-  anim.pause();
-
-  // The bezier function produces negative values 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');
-}, 'effect easing produces negative values with step-start keyframe');
-
-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)' });
-  anim.pause();
-
-  // The bezier function produces negative values in (0, 0.766312060)
-  anim.currentTime = 0;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 800;
-  assert_equals(getComputedStyle(target).left, '0px');
-  anim.currentTime = 1000;
-  assert_equals(getComputedStyle(target).left, '100px');
-}, 'effect easing produces negative values with step-end keyframe');
-
-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);
-  }
-
-  anim.pause();
-
-  // 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));
-  });
-}, 'effect easing produces values greater than 1 with keyframe easing ' +
-   'producing values 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;
-  }
-
-  anim.pause();
-
-  // 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))
-  });
-}, 'effect easing which produces values greater than 1 and the tangent on ' +
-   'the upper boundary is infinity with keyframe easing producing values ' +
-   'greater than 1');
-
-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);
-  }
-
-  anim.pause();
-
-  // 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));
-  });
-}, 'effect easing produces negative values with keyframe easing ' +
-   'producing negative values');
-
-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;
-  }
-
-  anim.pause();
-
-  // 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))
-  });
-}, 'effect easing which produces negative values and the tangent on ' +
-   'the lower boundary is infinity with keyframe easing producing ' +
-   'negative values');
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html
deleted file mode 100644
index e951bfd1..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html
+++ /dev/null
@@ -1,445 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>currentIteration of KeyframeEffectReadOnly getComputedTiming() tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
-<link rel="author" title="Daisuke Akatsuka" href="mailto:daisuke@mozilla-japan.org">
-<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 executeTests(tests, description) {
-  tests.forEach(function(currentTest) {
-    var testParams = '';
-    for (var attr in currentTest.input) {
-      testParams += ' ' + attr + ':' + currentTest.input[attr];
-    }
-    test(function(t) {
-      var div = createDiv(t);
-      var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input);
-      assert_equals(anim.effect.getComputedTiming().currentIteration,
-                    currentTest.before);
-      anim.currentTime = currentTest.input.delay || 0;
-      assert_equals(anim.effect.getComputedTiming().currentIteration,
-                    currentTest.active);
-      if (typeof currentTest.after !== 'undefined') {
-        anim.finish();
-        assert_equals(anim.effect.getComputedTiming().currentIteration,
-                      currentTest.after);
-      }
-    }, description + testParams);
-  });
-}
-
-async_test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 });
-  assert_equals(anim.effect.getComputedTiming().currentIteration, null);
-  anim.finished.then(t.step_func(function() {
-    assert_equals(anim.effect.getComputedTiming().currentIteration, null);
-    t.done();
-  }));
-}, 'Test currentIteration during before and after phase when fill is none');
-
-var gTests_zero_iterations = [
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2,
-    after: 2
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2,
-    after: 2
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2,
-    after: 2
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3,
-    after: 3
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3,
-    after: 3
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3,
-    after: 3
-  }
-];
-
-var gTests_integer_iterations = [
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 2,
-    after: 2
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 2
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 5,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 5,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3
-  }
-];
-
-var gTests_fractional_iterations = [
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 3,
-    after: 3
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 3
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 5,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2,
-    after: 5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 6,
-    after: 6
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3,
-    after: 6
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3
-  }
-];
-
-var gTests_infinity_iterations = [
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: Infinity,
-    after: Infinity
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: Infinity,
-    after: Infinity
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 2,
-    active: 2
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: Infinity,
-    after: Infinity
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 3,
-    active: 3
-  }
-];
-
-executeTests(gTests_zero_iterations, "Test zero iterations:");
-executeTests(gTests_integer_iterations, "Test integer iterations:");
-executeTests(gTests_fractional_iterations, "Test fractional iterations:");
-executeTests(gTests_infinity_iterations, "Test infinity iterations:");
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-expected.txt
deleted file mode 100644
index 4324d72..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-expected.txt
+++ /dev/null
@@ -1,44 +0,0 @@
-This is a testharness.js-based test.
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed without any KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by an empty KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a normal KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a double value KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by +Infinity KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by an Infinity duration KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by an auto duration KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by an Infinity iterations KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a negative Infinity iterations KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a NaN iterations KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a negative iterations KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by an auto fill KeyframeEffectReadOnly is not defined
-FAIL values of getComputedTiming() when a KeyframeEffectReadOnly is constructed by a forwards fill KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an empty KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a non-zero duration and default iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a non-zero duration and integral iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a non-zero duration and fractional iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an non-zero duration and infinite iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an non-zero duration and zero iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a zero duration and default iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a zero duration and fractional iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a zero duration and infinite iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a zero duration and zero iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an infinite duration and default iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an infinite duration and zero iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an infinite duration and fractional iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an infinite duration and infinite iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for an infinite duration and zero iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().activeDuration for a non-zero duration and invalid iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an empty KeyframeEffectOptions object KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for a non-zero duration and default iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for a non-zero duration and non-default iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for a non-zero duration and non-zero delay KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for a non-zero duration, non-zero delay and non-default iteration KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an infinite iteration count KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an infinite duration KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an infinite duration and delay KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an infinite duration and negative delay KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an non-zero duration and negative delay KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for an non-zero duration and negative delay greater than active duration KeyframeEffectReadOnly is not defined
-FAIL getComputedTiming().endTime for a zero duration and negative delay KeyframeEffectReadOnly is not defined
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html
deleted file mode 100644
index 4cecc1d..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html
+++ /dev/null
@@ -1,445 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>progress of KeyframeEffectReadOnly getComputedTiming() tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
-<link rel="author" title="Daisuke Akatsuka" href="mailto:daisuke@mozilla-japan.org">
-<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 executeTests(tests, description) {
-  tests.forEach(function(currentTest) {
-    var testParams = '';
-    for (var attr in currentTest.input) {
-      testParams += ' ' + attr + ':' + currentTest.input[attr];
-    }
-    test(function(t) {
-      var div = createDiv(t);
-      var anim = div.animate({ opacity: [ 0, 1 ] }, currentTest.input);
-      assert_equals(anim.effect.getComputedTiming().progress,
-                    currentTest.before);
-      anim.currentTime = currentTest.input.delay || 0;
-      assert_equals(anim.effect.getComputedTiming().progress,
-                    currentTest.active);
-      if (typeof currentTest.after !== 'undefined') {
-        anim.finish();
-        assert_equals(anim.effect.getComputedTiming().progress,
-                      currentTest.after);
-      }
-    }, description + testParams);
-  });
-}
-
-async_test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate({ opacity: [ 0, 1 ] }, { delay: 1 });
-  assert_equals(anim.effect.getComputedTiming().progress, null);
-  anim.finished.then(t.step_func(function() {
-    assert_equals(anim.effect.getComputedTiming().progress, null);
-    t.done();
-  }));
-}, 'Test progress during before and after phase when fill is none');
-
-var gTests_zero_iterations = [
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  },
-
-  {
-    input:    { iterations: 0,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0
-  }
-];
-
-var gTests_integer_iterations = [
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 1,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 1,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  }
-];
-
-var gTests_fractional_iterations = [
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 1,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 1
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: 3.5,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  }
-];
-
-var gTests_infinity_iterations = [
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 1,
-    after: 1
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 0,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5,
-    after: 0.5
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 2.5,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0.5,
-    active: 0.5
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: 0,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 1,
-    after: 1
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: 100,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  },
-
-  {
-    input:    { iterations: Infinity,
-                iterationStart: 3,
-                duration: Infinity,
-                delay: 1,
-                fill: 'both' },
-    before: 0,
-    active: 0
-  }
-];
-
-executeTests(gTests_zero_iterations, "Test zero iterations:");
-executeTests(gTests_integer_iterations, "Test integer iterations:");
-executeTests(gTests_fractional_iterations, "Test fractional iterations:");
-executeTests(gTests_infinity_iterations, "Test infinity iterations:");
-
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming.html
deleted file mode 100644
index 5f4c602..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming.html
+++ /dev/null
@@ -1,227 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>KeyframeEffectReadOnly getComputedTiming() tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#dom-animationeffectreadonly-getcomputedtiming">
-<link rel="author" title="Boris Chiou" href="mailto:boris.chiou@gmail.com">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></div>
-<script>
-"use strict";
-
-var target = document.getElementById("target");
-
-test(function(t) {
-  var effect = new KeyframeEffectReadOnly(target,
-                                          { left: ["10px", "20px"] });
-
-  var ct = effect.getComputedTiming();
-  assert_equals(ct.delay, 0, "computed delay");
-  assert_equals(ct.fill, "none", "computed fill");
-  assert_equals(ct.iterations, 1.0, "computed iterations");
-  assert_equals(ct.duration, 0, "computed duration");
-  assert_equals(ct.direction, "normal", "computed direction");
-}, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
-   "constructed without any KeyframeEffectOptions object");
-
-var gGetComputedTimingTests = [
-  { desc:     "an empty KeyframeEffectOptions object",
-    input:    { },
-    expected: { } },
-  { desc:     "a normal KeyframeEffectOptions object",
-    input:    { delay: 1000,
-                fill: "auto",
-                iterations: 5.5,
-                duration: "auto",
-                direction: "alternate" },
-    expected: { delay: 1000,
-                fill: "none",
-                iterations: 5.5,
-                duration: 0,
-                direction: "alternate" } },
-  { desc:     "a double value",
-    input:    3000,
-    timing:   { duration: 3000 },
-    expected: { delay: 0,
-                fill: "none",
-                iterations: 1,
-                duration: 3000,
-                direction: "normal" } },
-  { desc:     "+Infinity",
-    input:    Infinity,
-    expected: { duration: Infinity } },
-  { desc:     "an Infinity duration",
-    input:    { duration: Infinity },
-    expected: { duration: Infinity } },
-  { desc:     "an auto duration",
-    input:    { duration: "auto" },
-    expected: { duration: 0 } },
-  { desc:     "an Infinity iterations",
-    input:    { iterations: Infinity },
-    expected: { iterations: Infinity } },
-  { desc:     "a negative Infinity iterations",
-    input:    { iterations: -Infinity},
-    expected: { iterations: 1 } },
-  { desc:     "a NaN iterations",
-    input:    { iterations: NaN },
-    expected: { iterations: 1 } },
-  { desc:     "a negative iterations",
-    input:    { iterations: -1 },
-    expected: { iterations: 1 } },
-  { desc:     "an auto fill",
-    input:    { fill: "auto" },
-    expected: { fill: "none" } },
-  { desc:     "a forwards fill",
-    input:    { fill: "forwards" },
-    expected: { fill: "forwards" } }
-];
-
-gGetComputedTimingTests.forEach(function(stest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target,
-                                            { left: ["10px", "20px"] },
-                                            stest.input);
-
-    // Helper function to provide default expected values when the test does
-    // not supply them.
-    var expected = function(field, defaultValue) {
-      return field in stest.expected ? stest.expected[field] : defaultValue;
-    };
-
-    var ct = effect.getComputedTiming();
-    assert_equals(ct.delay, expected("delay", 0),
-                  "computed delay");
-    assert_equals(ct.fill, expected("fill", "none"),
-                  "computed fill");
-    assert_equals(ct.iterations, expected("iterations", 1),
-                  "computed iterations");
-    assert_equals(ct.duration, expected("duration", 0),
-                  "computed duration");
-    assert_equals(ct.direction, expected("direction", "normal"),
-                  "computed direction");
-
-  }, "values of getComputedTiming() when a KeyframeEffectReadOnly is " +
-     "constructed by " + stest.desc);
-});
-
-var gActiveDurationTests = [
-  { desc:     "an empty KeyframeEffectOptions object",
-    input:    { },
-    expected: 0 },
-  { desc:     "a non-zero duration and default iteration count",
-    input:    { duration: 1000 },
-    expected: 1000 },
-  { desc:     "a non-zero duration and integral iteration count",
-    input:    { duration: 1000, iterations: 7 },
-    expected: 7000 },
-  { desc:     "a non-zero duration and fractional iteration count",
-    input:    { duration: 1000, iterations: 2.5 },
-    expected: 2500 },
-  { desc:     "an non-zero duration and infinite iteration count",
-    input:    { duration: 1000, iterations: Infinity },
-    expected: Infinity },
-  { desc:     "an non-zero duration and zero iteration count",
-    input:    { duration: 1000, iterations: 0 },
-    expected: 0 },
-  { desc:     "a zero duration and default iteration count",
-    input:    { duration: 0 },
-    expected: 0 },
-  { desc:     "a zero duration and fractional iteration count",
-    input:    { duration: 0, iterations: 2.5 },
-    expected: 0 },
-  { desc:     "a zero duration and infinite iteration count",
-    input:    { duration: 0, iterations: Infinity },
-    expected: 0 },
-  { desc:     "a zero duration and zero iteration count",
-    input:    { duration: 0, iterations: 0 },
-    expected: 0 },
-  { desc:     "an infinite duration and default iteration count",
-    input:    { duration: Infinity },
-    expected: Infinity },
-  { desc:     "an infinite duration and zero iteration count",
-    input:    { duration: Infinity, iterations: 0 },
-    expected: 0 },
-  { desc:     "an infinite duration and fractional iteration count",
-    input:    { duration: Infinity, iterations: 2.5 },
-    expected: Infinity },
-  { desc:     "an infinite duration and infinite iteration count",
-    input:    { duration: Infinity, iterations: Infinity },
-    expected: Infinity },
-  { desc:     "an infinite duration and zero iteration count",
-    input:    { duration: Infinity, iterations: 0 },
-    expected: 0 },
-  { desc:     "a non-zero duration and invalid iteration count",
-    input:    { duration: 1000, iterations: "cabbage" },
-    expected: 1000 }
-];
-
-gActiveDurationTests.forEach(function(stest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target,
-                                            { left: ["10px", "20px"] },
-                                            stest.input);
-
-    assert_equals(effect.getComputedTiming().activeDuration,
-                  stest.expected);
-
-  }, "getComputedTiming().activeDuration for " + stest.desc);
-});
-
-var gEndTimeTests = [
-  { desc:     "an empty KeyframeEffectOptions object",
-    input:    { },
-    expected: 0 },
-  { desc:     "a non-zero duration and default iteration count",
-    input:    { duration: 1000 },
-    expected: 1000 },
-  { desc:     "a non-zero duration and non-default iteration count",
-    input:    { duration: 1000, iterations: 2.5 },
-    expected: 2500 },
-  { desc:     "a non-zero duration and non-zero delay",
-    input:    { duration: 1000, delay: 1500 },
-    expected: 2500 },
-  { desc:     "a non-zero duration, non-zero delay and non-default iteration",
-    input:    { duration: 1000, delay: 1500, iterations: 2 },
-    expected: 3500 },
-  { desc:     "an infinite iteration count",
-    input:    { duration: 1000, iterations: Infinity },
-    expected: Infinity },
-  { desc:     "an infinite duration",
-    input:    { duration: Infinity, iterations: 10 },
-    expected: Infinity },
-  { desc:     "an infinite duration and delay",
-    input:    { duration: Infinity, iterations: 10, delay: 1000 },
-    expected: Infinity },
-  { desc:     "an infinite duration and negative delay",
-    input:    { duration: Infinity, iterations: 10, delay: -1000 },
-    expected: Infinity },
-  { desc:     "an non-zero duration and negative delay",
-    input:    { duration: 1000, iterations: 2, delay: -1000 },
-    expected: 1000 },
-  { desc:     "an non-zero duration and negative delay greater than active " +
-              "duration",
-    input:    { duration: 1000, iterations: 2, delay: -3000 },
-    expected: -1000 },
-  { desc:     "a zero duration and negative delay",
-    input:    { duration: 0, iterations: 2, delay: -1000 },
-    expected: -1000 }
-];
-
-gEndTimeTests.forEach(function(stest) {
-  test(function(t) {
-    var effect = new KeyframeEffectReadOnly(target,
-                                            { left: ["10px", "20px"] },
-                                            stest.input);
-
-    assert_equals(effect.getComputedTiming().endTime,
-                  stest.expected);
-
-  }, "getComputedTiming().endTime for " + stest.desc);
-});
-
-done();
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling-expected.txt b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling-expected.txt
deleted file mode 100644
index 52d4f89..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling-expected.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-This is a testharness.js-based test.
-FAIL Overlapping keyframes at 0 and 1 use the appropriate value when the progress is outside the range [0, 1] assert_equals: When progress is negative, the first keyframe with a 0 offset should be used expected "0" but got "0.151456"
-PASS Overlapping keyframes between 0 and 1 use the appropriate value on each side of the overlap point 
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling.html b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling.html
deleted file mode 100644
index 613933c..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling.html
+++ /dev/null
@@ -1,75 +0,0 @@
-<!DOCTYPE html>
-<meta charset=utf-8>
-<title>Keyframe handling tests</title>
-<link rel="help" href="https://w3c.github.io/web-animations/#the-effect-value-of-a-keyframe-animation-effect">
-<link rel="author" title="Brian Birtles" href="mailto:bbirtles@mozilla.com">
-<script src="../../../../resources/testharness.js"></script>
-<script src="../../../../resources/testharnessreport.js"></script>
-<script src="../testcommon.js"></script>
-<body>
-<div id="log"></div>
-<div id="target"></div>
-<script>
-'use strict';
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate([ { offset: 0, opacity: 0 },
-                           { offset: 0, opacity: 0.1 },
-                           { offset: 0, opacity: 0.2 },
-                           { offset: 1, opacity: 0.8 },
-                           { offset: 1, opacity: 0.9 },
-                           { offset: 1, opacity: 1 } ],
-                         { duration: 1000,
-                           easing: 'cubic-bezier(0.5, -0.5, 0.5, 1.5)' });
-  assert_equals(getComputedStyle(div).opacity, '0.2',
-                'When progress is zero the last keyframe with offset 0 should'
-                + ' be used');
-  // http://cubic-bezier.com/#.5,-0.5,.5,1.5
-  // At t=0.15, the progress should be negative
-  anim.currentTime = 150;
-  assert_equals(getComputedStyle(div).opacity, '0',
-                'When progress is negative, the first keyframe with a 0 offset'
-                + ' should be used');
-  // At t=0.71, the progress should be just less than 1
-  anim.currentTime = 710;
-  assert_approx_equals(parseFloat(getComputedStyle(div).opacity), 0.8, 0.01,
-                'When progress is just less than 1, the first keyframe with an'
-                + ' offset of 1 should be used as the interval endpoint');
-  // At t=0.85, the progress should be > 1
-  anim.currentTime = 850;
-  assert_equals(getComputedStyle(div).opacity, '1',
-                'When progress is greater than 1.0, the last keyframe with a 1'
-                + ' offset should be used');
-  anim.finish();
-  assert_equals(getComputedStyle(div).opacity, '1',
-                'When progress is equal to 1.0, the last keyframe with a 1'
-                + ' offset should be used');
-}, 'Overlapping keyframes at 0 and 1 use the appropriate value when the'
-   + ' progress is outside the range [0, 1]');
-
-test(function(t) {
-  var div = createDiv(t);
-  var anim = div.animate([ { offset: 0, opacity: 0 },
-                           { offset: 0.5, opacity: 0.3 },
-                           { offset: 0.5, opacity: 0.5 },
-                           { offset: 0.5, opacity: 0.7 },
-                           { offset: 1, opacity: 1 } ], 1000);
-  anim.currentTime = 250;
-  assert_equals(getComputedStyle(div).opacity, '0.15',
-                'Before the overlap point, the first keyframe from the'
-                + ' overlap point should be used as interval endpoint');
-  anim.currentTime = 500;
-  assert_equals(getComputedStyle(div).opacity, '0.7',
-                'At the overlap point, the last keyframe from the'
-                + ' overlap point should be used as interval startpoint');
-  anim.currentTime = 750;
-  assert_equals(getComputedStyle(div).opacity, '0.85',
-                'After the overlap point, the last keyframe from the'
-                + ' overlap point should be used as interval startpoint');
-}, 'Overlapping keyframes between 0 and 1 use the appropriate value on each'
-   + ' side of the overlap point');
-
-done();
-</script>
-</body>
diff --git a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/testcommon.js b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/testcommon.js
deleted file mode 100644
index e7179cc1..0000000
--- a/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/testcommon.js
+++ /dev/null
@@ -1,166 +0,0 @@
-/*
-Distributed under both the W3C Test Suite License [1] and the W3C
-3-clause BSD License [2]. To contribute to a W3C Test Suite, see the
-policies and contribution forms [3].
-
-[1] http://www.w3.org/Consortium/Legal/2008/04-testsuite-license
-[2] http://www.w3.org/Consortium/Legal/2008/03-bsd-license
-[3] http://www.w3.org/2004/10/27-testcases
- */
-
-"use strict";
-
-var ANIMATION_END_TIME = 1000;
-var ANIMATION_TOP_DEFAULT = 300;
-var ANIMATION_TOP_0 = 10;
-var ANIMATION_TOP_0_5 = 100;
-var ANIMATION_TOP_1 = 200;
-
-var KEYFRAMES = [ {
-  top : ANIMATION_TOP_0 + 'px',
-  offset : 0
-}, {
-  top : ANIMATION_TOP_0_5 + 'px',
-  offset : 1 / 2
-}, {
-  top : ANIMATION_TOP_1 + 'px',
-  offset : 1
-} ];
-
-// creates new animation for given target
-function newAnimation(animationTarget) {
-  animationTarget.style.top = ANIMATION_TOP_DEFAULT + 'px';
-  return new Animation(animationTarget, KEYFRAMES, ANIMATION_END_TIME);
-}
-
-// creates div element, appends it to the document body and
-// removes the created element during test cleanup
-function createDiv(test, doc) {
-  if (!doc) {
-    doc = document;
-  }
-  var div = doc.createElement('div');
-  doc.body.appendChild(div);
-  test.add_cleanup(function() {
-    div.remove();
-  });
-  return div;
-}
-
-// Creates a style element with the specified rules, appends it to the document
-// head and removes the created element during test cleanup.
-// |rules| is an object. For example:
-// { '@keyframes anim': '' ,
-//   '.className': 'animation: anim 100s;' };
-// or
-// { '.className1::before': 'content: ""; width: 0px; transition: all 10s;',
-//   '.className2::before': 'width: 100px;' };
-// The object property name could be a keyframes name, or a selector.
-// The object property value is declarations which are property:value pairs
-// split by a space.
-function createStyle(test, rules, doc) {
-  if (!doc) {
-    doc = document;
-  }
-  var extraStyle = doc.createElement('style');
-  doc.head.appendChild(extraStyle);
-  if (rules) {
-    var sheet = extraStyle.sheet;
-    for (var selector in rules) {
-      sheet.insertRule(selector + '{' + rules[selector] + '}',
-                       sheet.cssRules.length);
-    }
-  }
-  test.add_cleanup(function() {
-    extraStyle.remove();
-  });
-}
-
-// Create a pseudo element
-function createPseudo(test, type) {
-  createStyle(test, { '@keyframes anim': '',
-                      ['.pseudo::' + type]: 'animation: anim 10s;' });
-  var div = createDiv(test);
-  div.classList.add('pseudo');
-  var anims = document.getAnimations();
-  assert_true(anims.length >= 1);
-  var anim = anims[anims.length - 1];
-  assert_equals(anim.effect.target.parentElement, div);
-  assert_equals(anim.effect.target.type, '::' + type);
-  anim.cancel();
-  return anim.effect.target;
-}
-
-// Returns the type name of given object
-function type(object) {
-  return Object.prototype.toString.call(object).slice(8, -1);
-}
-
-// 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));
-  }
-}
-
-function stepEnd(nsteps) {
-  return function stepEndClosure(x) {
-    return Math.floor(x * nsteps) / nsteps;
-  }
-}
-
-function stepStart(nsteps) {
-  return function stepStartClosure(x) {
-    var result = Math.floor(x * nsteps + 1.0) / nsteps;
-    return (result > 1.0) ? 1.0 : result;
-  }
-}
-
-function waitForAnimationFrames(frameCount) {
-  return new Promise(function(resolve, reject) {
-    function handleFrame() {
-      if (--frameCount <= 0) {
-        resolve();
-      } else {
-        window.requestAnimationFrame(handleFrame); // wait another frame
-      }
-    }
-    window.requestAnimationFrame(handleFrame);
-  });
-}
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index fefafd8e..b7da2bf6 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -3541,6 +3541,7 @@
     attribute @@toStringTag
     method constructor
     method enumerateDevices
+    method getSupportedConstraints
     method getUserMedia
 interface MediaElementAudioSourceNode : AudioSourceNode
     attribute @@toStringTag
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 3515acb..d2159afa 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -2007,6 +2007,8 @@
             'page/scrolling/ScrollState.h',
             'page/scrolling/ScrollStateCallback.cpp',
             'page/scrolling/ScrollStateCallback.h',
+            'page/scrolling/StickyPositionScrollingConstraints.cpp',
+            'page/scrolling/StickyPositionScrollingConstraints.h',
             'paint/BackgroundImageGeometry.cpp',
             'paint/BackgroundImageGeometry.h',
             'paint/BlockFlowPainter.cpp',
diff --git a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
index 1699b6a..a6482859 100644
--- a/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
+++ b/third_party/WebKit/Source/core/css/CSSGridTemplateAreasValue.cpp
@@ -46,17 +46,10 @@
 
 static String stringForPosition(const NamedGridAreaMap& gridAreaMap, size_t row, size_t column)
 {
-    Vector<String> candidates;
-
     for (const auto& item : gridAreaMap) {
         const GridArea& area = item.value;
-        if (row >= area.rows.startLine() && row < area.rows.endLine())
-            candidates.append(item.key);
-    }
-
-    for (const auto& item : gridAreaMap) {
-        const GridArea& area = item.value;
-        if (column >= area.columns.startLine() && column < area.columns.endLine() && candidates.contains(item.key))
+        if (row >= area.rows.startLine() && row < area.rows.endLine()
+            && column >= area.columns.startLine() && column < area.columns.endLine())
             return item.key;
     }
 
@@ -67,13 +60,13 @@
 {
     StringBuilder builder;
     for (size_t row = 0; row < m_rowCount; ++row) {
-        builder.append('\"');
+        builder.append('"');
         for (size_t column = 0; column < m_columnCount; ++column) {
             builder.append(stringForPosition(m_gridAreaMap, row, column));
             if (column != m_columnCount - 1)
                 builder.append(' ');
         }
-        builder.append('\"');
+        builder.append('"');
         if (row != m_rowCount - 1)
             builder.append(' ');
     }
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
index 0abc943..a564db6 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleAdjuster.cpp
@@ -196,7 +196,7 @@
         || style.hasFilterInducingProperty()
         || style.hasBlendMode()
         || style.hasIsolation()
-        || style.position() == FixedPosition
+        || style.hasViewportConstrainedPosition()
         || isInTopLayer(element, style)
         || hasWillChangeThatCreatesStackingContext(style)
         || style.containsPaint()))
@@ -436,6 +436,12 @@
         && style.position() == RelativePosition)
         style.setPosition(StaticPosition);
 
+    // Cannot support position: sticky for table columns and column groups because current code is only doing
+    // background painting through columns / column groups
+    if ((style.display() == TABLE_COLUMN_GROUP || style.display() == TABLE_COLUMN)
+        && style.position() == StickyPosition)
+        style.setPosition(StaticPosition);
+
     // writing-mode does not apply to table row groups, table column groups, table rows, and table columns.
     // FIXME: Table cells should be allowed to be perpendicular or flipped with respect to the table, though.
     if (style.display() == TABLE_COLUMN || style.display() == TABLE_COLUMN_GROUP || style.display() == TABLE_FOOTER_GROUP
diff --git a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
index c6bc94a..4dbd678 100644
--- a/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/StyleBuilderCustom.cpp
@@ -66,6 +66,7 @@
 #include "core/css/resolver/TransformBuilder.h"
 #include "core/frame/LocalFrame.h"
 #include "core/frame/Settings.h"
+#include "core/style/ContentData.h"
 #include "core/style/CounterContent.h"
 #include "core/style/ComputedStyle.h"
 #include "core/style/ComputedStyleConstants.h"
@@ -646,7 +647,7 @@
 
 void StyleBuilderFunctions::applyInitialCSSPropertyContent(StyleResolverState& state)
 {
-    state.style()->clearContent();
+    state.style()->setContent(nullptr);
 }
 
 void StyleBuilderFunctions::applyInheritCSSPropertyContent(StyleResolverState&)
@@ -657,20 +658,23 @@
 
 void StyleBuilderFunctions::applyValueCSSPropertyContent(StyleResolverState& state, CSSValue* value)
 {
-    state.style()->clearContent();
     if (value->isPrimitiveValue()) {
         ASSERT(toCSSPrimitiveValue(*value).getValueID() == CSSValueNormal || toCSSPrimitiveValue(*value).getValueID() == CSSValueNone);
+        state.style()->setContent(nullptr);
         return;
     }
 
-    // TODO(timloh): This logic shouldn't be split across here and ComputedStyle.cpp
+    ContentData* firstContent = nullptr;
+    ContentData* prevContent = nullptr;
     for (auto& item : toCSSValueList(*value)) {
+        ContentData* nextContent = nullptr;
+        // TODO(timloh): This should just call styleImage to handle all the different image types
         if (item->isImageGeneratorValue()) {
-            state.style()->setContent(StyleGeneratedImage::create(toCSSImageGeneratorValue(*item)));
+            nextContent = ContentData::create(StyleGeneratedImage::create(toCSSImageGeneratorValue(*item)));
         } else if (item->isImageSetValue()) {
-            state.style()->setContent(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(*item)));
+            nextContent = ContentData::create(state.elementStyleResources().setOrPendingFromValue(CSSPropertyContent, toCSSImageSetValue(*item)));
         } else if (item->isImageValue()) {
-            state.style()->setContent(state.elementStyleResources().cachedOrPendingFromValue(CSSPropertyContent, toCSSImageValue(*item)));
+            nextContent = ContentData::create(state.elementStyleResources().cachedOrPendingFromValue(CSSPropertyContent, toCSSImageValue(*item)));
         } else if (item->isCounterValue()) {
             CSSCounterValue* counterValue = toCSSCounterValue(item.get());
             EListStyleType listStyleType = NoneListStyle;
@@ -678,39 +682,59 @@
             if (listStyleIdent != CSSValueNone)
                 listStyleType = static_cast<EListStyleType>(listStyleIdent - CSSValueDisc);
             OwnPtr<CounterContent> counter = adoptPtr(new CounterContent(AtomicString(counterValue->identifier()), listStyleType, AtomicString(counterValue->separator())));
-            state.style()->setContent(counter.release());
-        } else if (item->isFunctionValue()) {
-            CSSFunctionValue* functionValue = toCSSFunctionValue(item.get());
-            ASSERT(functionValue->functionType() == CSSValueAttr);
-            // FIXME: Can a namespace be specified for an attr(foo)?
-            if (state.style()->styleType() == PseudoIdNone)
-                state.style()->setUnique();
-            else
-                state.parentStyle()->setUnique();
-            QualifiedName attr(nullAtom, AtomicString(toCSSCustomIdentValue(functionValue->item(0))->value()), nullAtom);
-            const AtomicString& value = state.element()->getAttribute(attr);
-            state.style()->setContent(value.isNull() ? emptyString() : value.getString());
-        } else if (item->isStringValue()) {
-            state.style()->setContent(toCSSStringValue(*item).value().impl());
-        } else {
+            nextContent = ContentData::create(counter.release());
+        } else if (item->isPrimitiveValue()) {
+            QuoteType quoteType;
             switch (toCSSPrimitiveValue(*item).getValueID()) {
-            case CSSValueOpenQuote:
-                state.style()->setContent(OPEN_QUOTE);
-                break;
-            case CSSValueCloseQuote:
-                state.style()->setContent(CLOSE_QUOTE);
-                break;
-            case CSSValueNoOpenQuote:
-                state.style()->setContent(NO_OPEN_QUOTE);
-                break;
-            case CSSValueNoCloseQuote:
-                state.style()->setContent(NO_CLOSE_QUOTE);
-                break;
             default:
                 ASSERT_NOT_REACHED();
+            case CSSValueOpenQuote:
+                quoteType = OPEN_QUOTE;
+                break;
+            case CSSValueCloseQuote:
+                quoteType = CLOSE_QUOTE;
+                break;
+            case CSSValueNoOpenQuote:
+                quoteType = NO_OPEN_QUOTE;
+                break;
+            case CSSValueNoCloseQuote:
+                quoteType = NO_CLOSE_QUOTE;
+                break;
             }
+            nextContent = ContentData::create(quoteType);
+        } else {
+            String string;
+            if (item->isFunctionValue()) {
+                CSSFunctionValue* functionValue = toCSSFunctionValue(item.get());
+                ASSERT(functionValue->functionType() == CSSValueAttr);
+                // FIXME: Can a namespace be specified for an attr(foo)?
+                if (state.style()->styleType() == PseudoIdNone)
+                    state.style()->setUnique();
+                else
+                    state.parentStyle()->setUnique();
+                QualifiedName attr(nullAtom, AtomicString(toCSSCustomIdentValue(functionValue->item(0))->value()), nullAtom);
+                const AtomicString& value = state.element()->getAttribute(attr);
+                string = value.isNull() ? emptyString() : value.getString();
+            } else {
+                string = toCSSStringValue(*item).value();
+            }
+            if (prevContent && prevContent->isText()) {
+                TextContentData* textContent = toTextContentData(prevContent);
+                textContent->setText(textContent->text() + string);
+                continue;
+            }
+            nextContent = ContentData::create(string);
         }
+
+        if (!firstContent)
+            firstContent = nextContent;
+        else
+            prevContent->setNext(nextContent);
+
+        prevContent = nextContent;
     }
+    ASSERT(firstContent);
+    state.style()->setContent(firstContent);
 }
 
 void StyleBuilderFunctions::applyValueCSSPropertyWebkitLocale(StyleResolverState& state, CSSValue* value)
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index ac7978e7..d37c506 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -136,6 +136,7 @@
     , m_safeToPropagateScrollToParent(true)
     , m_isTrackingPaintInvalidations(false)
     , m_scrollCorner(nullptr)
+    , m_stickyPositionObjectCount(0)
     , m_inputEventsScaleFactorForEmulation(1)
     , m_layoutSizeFixedToFrameSize(true)
     , m_didScrollTimer(this, &FrameView::didScrollTimerFired)
@@ -1601,6 +1602,14 @@
     if (!hasViewportConstrainedObjects())
         return;
 
+    // Update sticky position objects which are stuck to the viewport.
+    for (const auto& viewportConstrainedObject : *m_viewportConstrainedObjects) {
+        LayoutObject* layoutObject = viewportConstrainedObject;
+        PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
+        if (layoutObject->style()->position() == StickyPosition)
+            layer->updateLayerPosition();
+    }
+
     // If there fixed position elements, scrolling may cause compositing layers to change.
     // Update widget and layer positions after scrolling, but only if we're not inside of
     // layout.
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index 1bcdcdf..8ed74dc 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -201,6 +201,11 @@
     const ViewportConstrainedObjectSet* viewportConstrainedObjects() const { return m_viewportConstrainedObjects.get(); }
     bool hasViewportConstrainedObjects() const { return m_viewportConstrainedObjects && m_viewportConstrainedObjects->size() > 0; }
 
+    // Sticky objects.
+    void addStickyPositionObject() { ++m_stickyPositionObjectCount; }
+    void removeStickyPositionObject() { --m_stickyPositionObjectCount; }
+    bool hasStickyPositionObjects() const { return m_stickyPositionObjectCount; }
+
     // Objects with background-attachment:fixed.
     void addBackgroundAttachmentFixedObject(LayoutObject*);
     void removeBackgroundAttachmentFixedObject(LayoutObject*);
@@ -824,6 +829,7 @@
     Member<ScrollableAreaSet> m_animatingScrollableAreas;
     OwnPtr<ResizerAreaSet> m_resizerAreas;
     OwnPtr<ViewportConstrainedObjectSet> m_viewportConstrainedObjects;
+    unsigned m_stickyPositionObjectCount;
     ViewportConstrainedObjectSet m_backgroundAttachmentFixedObjects;
     Member<FrameViewAutoSizeInfo> m_autoSizeInfo;
 
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
index a12d3e5d..1c32294d 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameView.cpp
@@ -4,6 +4,7 @@
 
 #include "core/frame/RemoteFrameView.h"
 
+#include "core/frame/FrameView.h"
 #include "core/frame/RemoteFrame.h"
 #include "core/html/HTMLFrameOwnerElement.h"
 #include "core/layout/LayoutPart.h"
@@ -20,6 +21,12 @@
 {
 }
 
+void RemoteFrameView::setParent(Widget* parent)
+{
+    Widget::setParent(parent);
+    frameRectsChanged();
+}
+
 RemoteFrameView* RemoteFrameView::create(RemoteFrame* remoteFrame)
 {
     RemoteFrameView* view = new RemoteFrameView(remoteFrame);
@@ -63,7 +70,13 @@
 
 void RemoteFrameView::frameRectsChanged()
 {
-    m_remoteFrame->frameRectsChanged(frameRect());
+    // Update the rect to reflect the position of the frame relative to the
+    // containing local frame root. The position of the local root within
+    // any remote frames, if any, is accounted for by the embedder.
+    IntRect newRect = frameRect();
+    if (parent() && parent()->isFrameView())
+        newRect = parent()->convertToRootFrame(toFrameView(parent())->contentsToFrame(newRect));
+    m_remoteFrame->frameRectsChanged(newRect);
 }
 
 void RemoteFrameView::hide()
diff --git a/third_party/WebKit/Source/core/frame/RemoteFrameView.h b/third_party/WebKit/Source/core/frame/RemoteFrameView.h
index 3eeb6c3e..ab69eae 100644
--- a/third_party/WebKit/Source/core/frame/RemoteFrameView.h
+++ b/third_party/WebKit/Source/core/frame/RemoteFrameView.h
@@ -20,6 +20,7 @@
     ~RemoteFrameView() override;
 
     bool isRemoteFrameView() const override { return true; }
+    void setParent(Widget*) override;
 
     RemoteFrame& frame() const
     {
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
index 92f9d5a..74e3636 100644
--- a/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentHelper.cpp
@@ -47,11 +47,6 @@
 
 AutoplayExperimentHelper::~AutoplayExperimentHelper()
 {
-#if !ENABLE(OILPAN)
-    // We can't do this during destruction in oilpan, since we rely on the
-    // client to still be alive.
-    dispose();
-#endif
 }
 
 void AutoplayExperimentHelper::dispose()
diff --git a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
index 79f7d5a..9f0381e 100644
--- a/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLInputElement.cpp
@@ -168,19 +168,6 @@
 
 HTMLInputElement::~HTMLInputElement()
 {
-#if !ENABLE(OILPAN)
-    // Need to remove form association while this is still an HTMLInputElement
-    // so that virtual functions are called correctly.
-    setForm(0);
-    // setForm(0) may register this to a TreeScope-level radio button group.
-    // We should unregister it to avoid accessing a deleted object.
-    if (type() == InputTypeNames::radio)
-        treeScope().radioButtonGroupScope().removeButton(this);
-
-    // TODO(dtapuska): Make this passive touch listener see crbug.com/584438
-    if (m_hasTouchEventHandler && document().frameHost())
-        document().frameHost()->eventHandlerRegistry().didRemoveEventHandler(*this, EventHandlerRegistry::TouchEventBlocking);
-#endif
 }
 
 const AtomicString& HTMLInputElement::name() const
@@ -1169,6 +1156,7 @@
     setAutofilled(false);
 }
 
+// TODO(Oilpan): It's nasty to return a void* pointer. Return ClickHandlingState* instead.
 void* HTMLInputElement::preDispatchEventHandler(Event* event)
 {
     if (event->type() == EventTypeNames::textInput && m_inputTypeView->shouldSubmitImplicitly(event)) {
@@ -1179,12 +1167,7 @@
         return nullptr;
     if (!event->isMouseEvent() || toMouseEvent(event)->button() != LeftButton)
         return nullptr;
-#if ENABLE(OILPAN)
     return m_inputTypeView->willDispatchClick();
-#else
-    // FIXME: Check whether there are any cases where this actually ends up leaking.
-    return m_inputTypeView->willDispatchClick().leakPtr();
-#endif
 }
 
 void HTMLInputElement::postDispatchEventHandler(Event* event, void* dataFromPreDispatch)
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
index de12264..1b3522c 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -162,14 +162,6 @@
 
 HTMLLinkElement::~HTMLLinkElement()
 {
-#if !ENABLE(OILPAN)
-    m_sizes->setObserver(nullptr);
-    m_relList->setObserver(nullptr);
-    m_link.clear();
-    if (inShadowIncludingDocument())
-        document().styleEngine().removeStyleSheetCandidateNode(this);
-    linkLoadEventSender().cancelEvent(this);
-#endif
 }
 
 void HTMLLinkElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value)
@@ -494,10 +486,6 @@
 
 LinkStyle::~LinkStyle()
 {
-#if !ENABLE(OILPAN)
-    if (m_sheet)
-        m_sheet->clearOwnerNode();
-#endif
 }
 
 Document& LinkStyle::document()
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
index 2d84e105..10a307e 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.cpp
@@ -417,7 +417,6 @@
     , m_processingPreferenceChange(false)
     , m_remoteRoutesAvailable(false)
     , m_playingRemotely(false)
-    , m_isFinalizing(false)
     , m_inOverlayFullscreenVideo(false)
     , m_audioTracks(AudioTrackList::create(*this))
     , m_videoTracks(VideoTrackList::create(*this))
@@ -428,13 +427,8 @@
     , m_autoplayHelperClient(AutoplayHelperClientImpl::create(this))
     , m_autoplayHelper(AutoplayExperimentHelper::create(m_autoplayHelperClient.get()))
     , m_remotePlaybackClient(nullptr)
-#if !ENABLE(OILPAN)
-    , m_weakPtrFactory(this)
-#endif
 {
-#if ENABLE(OILPAN)
     ThreadState::current()->registerPreFinalizer(this);
-#endif
 
     WTF_LOG(Media, "HTMLMediaElement::HTMLMediaElement(%p)", this);
 
@@ -451,41 +445,6 @@
 {
     WTF_LOG(Media, "HTMLMediaElement::~HTMLMediaElement(%p)", this);
 
-#if !ENABLE(OILPAN)
-    // Destruction of the autoplay helper requires the client, so be sure that
-    // this happens before the client is destructed.
-    if (m_autoplayHelper)
-        m_autoplayHelper.clear();
-
-    // HTMLMediaElement and m_asyncEventQueue always become unreachable
-    // together. So HTMLMediaElement and m_asyncEventQueue are destructed in
-    // the same GC. We don't need to close it explicitly in Oilpan.
-    m_asyncEventQueue->close();
-
-    setShouldDelayLoadEvent(false);
-
-    if (m_textTracks)
-        m_textTracks->clearOwner();
-    m_audioTracks->shutdown();
-    m_videoTracks->shutdown();
-
-    closeMediaSource();
-
-    removeElementFromDocumentMap(this, &document());
-
-    // Destroying the player may cause a resource load to be canceled,
-    // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being
-    // called via ResourceFetch::didLoadResource() then
-    // FrameLoader::checkCompleted(). To prevent load event dispatching during
-    // object destruction, we use Document::incrementLoadEventDelayCount().
-    // See http://crbug.com/275223 for more details.
-    document().incrementLoadEventDelayCount();
-
-    clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
-
-    document().decrementLoadEventDelayCount();
-#endif
-
     // m_audioSourceNode is explicitly cleared by AudioNode::dispose().
     // Since AudioNode::dispose() is guaranteed to be always called before
     // the AudioNode is destructed, m_audioSourceNode is explicitly cleared
@@ -493,51 +452,22 @@
     ASSERT(!m_audioSourceNode);
 }
 
-#if ENABLE(OILPAN)
 void HTMLMediaElement::dispose()
 {
-    // This must happen before we're destructed.
-    if (m_autoplayHelper)
-        m_autoplayHelper->dispose();
+    closeMediaSource();
 
-    // If the HTMLMediaElement dies with the Document we are not
-    // allowed to touch the Document to adjust delay load event counts
-    // from the destructor, as the Document could have been already
-    // destructed.
-    //
-    // Work around that restriction by accessing the Document from
-    // a prefinalizer action instead, updating its delayed load count.
-    // If needed - if the Document has been detached and informed its
-    // ContextLifecycleObservers (which HTMLMediaElement is) that
-    // it is being destroyed, the connection to the Document will
-    // have been severed already, but in that case there is no need
-    // to update the delayed load count. But if the Document hasn't
-    // been detached cleanly from any frame or it isn't dying in the
-    // same GC, we do update the delayed load count from the prefinalizer.
-    if (ActiveDOMObject::getExecutionContext())
-        setShouldDelayLoadEvent(false);
-
-    // If the MediaSource object survived, notify that the media element
-    // didn't.
-    if (Heap::isHeapObjectAlive(m_mediaSource))
-        closeMediaSource();
-
-    // Oilpan: the player must be released, but the player object
-    // cannot safely access this player client any longer as parts of
-    // it may have been finalized already (like the media element's
-    // supplementable table.)  Handled for now by entering an
-    // is-finalizing state, which is explicitly checked for if the
-    // player tries to access the media element during shutdown.
-    //
-    // FIXME: Oilpan: move the media player to the heap instead and
-    // avoid having to finalize it from here; this whole #if block
-    // could then be removed (along with the state bit it depends on.)
-    // crbug.com/378229
-    m_isFinalizing = true;
+    // Destroying the player may cause a resource load to be canceled,
+    // which could result in LocalDOMWindow::dispatchWindowLoadEvent() being
+    // called via ResourceFetch::didLoadResource() then
+    // FrameLoader::checkCompleted(). To prevent load event dispatching during
+    // object destruction, we use Document::incrementLoadEventDelayCount().
+    // See http://crbug.com/275223 for more details.
+    setShouldDelayLoadEvent(true);
 
     clearMediaPlayerAndAudioSourceProviderClientWithoutLocking();
+
+    setShouldDelayLoadEvent(false);
 }
-#endif
 
 void HTMLMediaElement::didMoveToNewDocument(Document& oldDocument)
 {
@@ -3645,11 +3575,7 @@
         return;
 
     // If either of the layers is null we need to enable or disable compositing. This is done by triggering a style recalc.
-    if ((!m_webLayer || !webLayer)
-#if ENABLE(OILPAN)
-        && !m_isFinalizing
-#endif
-        )
+    if (!m_webLayer || !webLayer)
         setNeedsCompositingUpdate();
 
     if (m_webLayer)
@@ -3939,11 +3865,4 @@
     return result;
 }
 
-#if !ENABLE(OILPAN)
-WeakPtr<HTMLMediaElement> HTMLMediaElement::createWeakPtr()
-{
-    return m_weakPtrFactory.createWeakPtr();
-}
-#endif
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaElement.h b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
index 019cb65..3aa0db3 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaElement.h
@@ -42,10 +42,6 @@
 #include "public/platform/WebMediaPlayerSource.h"
 #include "public/platform/WebMimeRegistry.h"
 
-#if !ENABLE(OILPAN)
-#include "wtf/WeakPtr.h"
-#endif
-
 namespace blink {
 
 class AudioSourceProviderClient;
@@ -272,16 +268,10 @@
     WebRemotePlaybackClient* remotePlaybackClient() { return m_remotePlaybackClient; }
     void setRemotePlaybackClient(WebRemotePlaybackClient*);
 
-#if !ENABLE(OILPAN)
-    WeakPtr<HTMLMediaElement> createWeakPtr();
-#endif
-
 protected:
     HTMLMediaElement(const QualifiedName&, Document&);
     ~HTMLMediaElement() override;
-#if ENABLE(OILPAN)
     void dispose();
-#endif
 
     void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override;
     void finishParsingChildren() final;
@@ -574,7 +564,6 @@
     bool m_processingPreferenceChange : 1;
     bool m_remoteRoutesAvailable : 1;
     bool m_playingRemotely : 1;
-    bool m_isFinalizing : 1;
     // Whether this element is in overlay fullscreen mode.
     bool m_inOverlayFullscreenVideo : 1;
 
@@ -591,7 +580,7 @@
     ExceptionCode m_playPromiseErrorCode;
 
     // This is a weak reference, since m_audioSourceNode holds a reference to us.
-    // FIXME: Oilpan: Consider making this a strongly traced pointer with oilpan where strong cycles are not a problem.
+    // TODO(Oilpan): Consider making this a strongly traced pointer with oilpan where strong cycles are not a problem.
     GC_PLUGIN_IGNORE("http://crbug.com/404577")
     WeakMember<AudioSourceProviderClient> m_audioSourceNode;
 
@@ -656,10 +645,6 @@
 
     WebRemotePlaybackClient* m_remotePlaybackClient;
 
-#if !ENABLE(OILPAN)
-    WeakPtrFactory<HTMLMediaElement> m_weakPtrFactory;
-#endif
-
     static URLRegistry* s_mediaStreamRegistry;
 };
 
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.cpp b/third_party/WebKit/Source/core/html/ImageDocument.cpp
index 112fc81..0de08f1 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.cpp
+++ b/third_party/WebKit/Source/core/html/ImageDocument.cpp
@@ -422,14 +422,6 @@
     return frame()->isMainFrame();
 }
 
-#if !ENABLE(OILPAN)
-void ImageDocument::dispose()
-{
-    m_imageElement = nullptr;
-    HTMLDocument::dispose();
-}
-#endif
-
 DEFINE_TRACE(ImageDocument)
 {
     visitor->trace(m_imageElement);
diff --git a/third_party/WebKit/Source/core/html/ImageDocument.h b/third_party/WebKit/Source/core/html/ImageDocument.h
index f912918..7602b27 100644
--- a/third_party/WebKit/Source/core/html/ImageDocument.h
+++ b/third_party/WebKit/Source/core/html/ImageDocument.h
@@ -58,9 +58,6 @@
     explicit ImageDocument(const DocumentInit&);
 
     DocumentParser* createParser() override;
-#if !ENABLE(OILPAN)
-    void dispose() override;
-#endif
 
     void createDocumentStructure();
 
diff --git a/third_party/WebKit/Source/core/html/LabelsNodeList.cpp b/third_party/WebKit/Source/core/html/LabelsNodeList.cpp
index cb881e7..9764cdb 100644
--- a/third_party/WebKit/Source/core/html/LabelsNodeList.cpp
+++ b/third_party/WebKit/Source/core/html/LabelsNodeList.cpp
@@ -39,9 +39,6 @@
 
 LabelsNodeList::~LabelsNodeList()
 {
-#if !ENABLE(OILPAN)
-    ownerNode().nodeLists()->removeCache(this, LabelsNodeListType);
-#endif
 }
 
 bool LabelsNodeList::elementMatches(const Element& element) const
diff --git a/third_party/WebKit/Source/core/html/RadioNodeList.cpp b/third_party/WebKit/Source/core/html/RadioNodeList.cpp
index f0f503a..c05799c 100644
--- a/third_party/WebKit/Source/core/html/RadioNodeList.cpp
+++ b/third_party/WebKit/Source/core/html/RadioNodeList.cpp
@@ -46,9 +46,6 @@
 
 RadioNodeList::~RadioNodeList()
 {
-#if !ENABLE(OILPAN)
-    ownerNode().nodeLists()->removeCache(this, type(), m_name);
-#endif
 }
 
 static inline HTMLInputElement* toRadioButtonInputElement(Element& element)
diff --git a/third_party/WebKit/Source/core/html/RelList.cpp b/third_party/WebKit/Source/core/html/RelList.cpp
index 4b726e5..3b4bd7d 100644
--- a/third_party/WebKit/Source/core/html/RelList.cpp
+++ b/third_party/WebKit/Source/core/html/RelList.cpp
@@ -15,20 +15,6 @@
 
 RelList::RelList(Element* element) : DOMTokenList(nullptr), m_element(element) { }
 
-#if !ENABLE(OILPAN)
-void RelList::ref()
-{
-    m_element->ref();
-    DOMTokenList::ref();
-}
-
-void RelList::deref()
-{
-    m_element->deref();
-    DOMTokenList::deref();
-}
-#endif
-
 unsigned RelList::length() const
 {
     return !m_element->fastGetAttribute(relAttr).isEmpty() ? m_relValues.size() : 0;
diff --git a/third_party/WebKit/Source/core/html/RelList.h b/third_party/WebKit/Source/core/html/RelList.h
index 9349656..0da3940 100644
--- a/third_party/WebKit/Source/core/html/RelList.h
+++ b/third_party/WebKit/Source/core/html/RelList.h
@@ -19,11 +19,6 @@
         return new RelList(element);
     }
 
-#if !ENABLE(OILPAN)
-    void ref() override;
-    void deref() override;
-#endif
-
     unsigned length() const override;
     const AtomicString item(unsigned index) const override;
 
diff --git a/third_party/WebKit/Source/core/html/ValidityState.h b/third_party/WebKit/Source/core/html/ValidityState.h
index 64135686..d7857b1 100644
--- a/third_party/WebKit/Source/core/html/ValidityState.h
+++ b/third_party/WebKit/Source/core/html/ValidityState.h
@@ -40,11 +40,6 @@
     }
     DEFINE_INLINE_TRACE() { visitor->trace(m_control); }
 
-#if !ENABLE(OILPAN)
-    void ref() { m_control->ref(); }
-    void deref() { m_control->deref(); }
-#endif
-
     String validationMessage() const;
 
     void setCustomErrorMessage(const String&);
diff --git a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
index 71688ee..bed999c 100644
--- a/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
+++ b/third_party/WebKit/Source/core/html/canvas/CanvasRenderingContext.h
@@ -64,11 +64,6 @@
     static ContextType contextTypeFromId(const String& id);
     static ContextType resolveContextTypeAliases(ContextType);
 
-#if !ENABLE(OILPAN)
-    void ref() { m_canvas->ref(); }
-    void deref() { m_canvas->deref(); }
-#endif
-
     HTMLCanvasElement* canvas() const { return m_canvas; }
 
     virtual ContextType getContextType() const = 0;
diff --git a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
index e136a2b..01794a9 100644
--- a/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
+++ b/third_party/WebKit/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -454,10 +454,6 @@
 
 DateTimeEditElement::~DateTimeEditElement()
 {
-#if !ENABLE(OILPAN)
-    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
-        m_fields[fieldIndex]->removeEventHandler();
-#endif
 }
 
 DEFINE_TRACE(DateTimeEditElement)
diff --git a/third_party/WebKit/Source/core/html/track/CueTimeline.cpp b/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
index 56cfb40..b365915 100644
--- a/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
+++ b/third_party/WebKit/Source/core/html/track/CueTimeline.cpp
@@ -131,13 +131,11 @@
 
     HTMLMediaElement& mediaElement = this->mediaElement();
 
-#if !ENABLE(OILPAN)
     // Don't run the "time marches on" algorithm if the document has been
     // detached. This primarily guards against dispatch of events w/
     // HTMLTrackElement targets.
     if (mediaElement.document().isDetached())
         return;
-#endif
 
     // https://html.spec.whatwg.org/#time-marches-on
 
diff --git a/third_party/WebKit/Source/core/html/track/LoadableTextTrack.cpp b/third_party/WebKit/Source/core/html/track/LoadableTextTrack.cpp
index 51540ac..f67c616 100644
--- a/third_party/WebKit/Source/core/html/track/LoadableTextTrack.cpp
+++ b/third_party/WebKit/Source/core/html/track/LoadableTextTrack.cpp
@@ -39,18 +39,8 @@
 
 LoadableTextTrack::~LoadableTextTrack()
 {
-#if !ENABLE(OILPAN)
-    ASSERT(!m_trackElement);
-#endif
 }
 
-#if !ENABLE(OILPAN)
-void LoadableTextTrack::clearTrackElement()
-{
-    m_trackElement = nullptr;
-}
-#endif
-
 bool LoadableTextTrack::isDefault() const
 {
     ASSERT(m_trackElement);
@@ -60,11 +50,6 @@
 void LoadableTextTrack::setMode(const AtomicString& mode)
 {
     TextTrack::setMode(mode);
-#if !ENABLE(OILPAN)
-    if (!m_trackElement)
-        return;
-#endif
-
     if (m_trackElement->getReadyState() == HTMLTrackElement::NONE)
         m_trackElement->scheduleLoad();
 }
diff --git a/third_party/WebKit/Source/core/html/track/LoadableTextTrack.h b/third_party/WebKit/Source/core/html/track/LoadableTextTrack.h
index 7ed7d2c..22eecc1 100644
--- a/third_party/WebKit/Source/core/html/track/LoadableTextTrack.h
+++ b/third_party/WebKit/Source/core/html/track/LoadableTextTrack.h
@@ -50,9 +50,6 @@
 
     size_t trackElementIndex();
     HTMLTrackElement* trackElement() { return m_trackElement; }
-#if !ENABLE(OILPAN)
-    void clearTrackElement();
-#endif
 
     bool isDefault() const override;
 
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
index 7292349..8fd0d1f 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
+++ b/third_party/WebKit/Source/core/html/track/TextTrackList.cpp
@@ -43,14 +43,6 @@
 
 TextTrackList::~TextTrackList()
 {
-#if !ENABLE(OILPAN)
-    ASSERT(!m_owner);
-
-    // TextTrackList and m_asyncEventQueue always become unreachable
-    // together. So TextTrackList and m_asyncEventQueue are destructed in the
-    // same GC. We don't need to close it explicitly in Oilpan.
-    m_asyncEventQueue->close();
-#endif
 }
 
 unsigned TextTrackList::length() const
@@ -262,13 +254,6 @@
     return m_owner ? m_owner->getExecutionContext() : 0;
 }
 
-#if !ENABLE(OILPAN)
-void TextTrackList::clearOwner()
-{
-    m_owner = nullptr;
-}
-#endif
-
 void TextTrackList::scheduleTrackEvent(const AtomicString& eventName, TextTrack* track)
 {
     m_asyncEventQueue->enqueueEvent(TrackEvent::create(eventName, track));
diff --git a/third_party/WebKit/Source/core/html/track/TextTrackList.h b/third_party/WebKit/Source/core/html/track/TextTrackList.h
index c4c17c1d..c9fa5ef 100644
--- a/third_party/WebKit/Source/core/html/track/TextTrackList.h
+++ b/third_party/WebKit/Source/core/html/track/TextTrackList.h
@@ -66,9 +66,6 @@
     DEFINE_ATTRIBUTE_EVENT_LISTENER(change);
     DEFINE_ATTRIBUTE_EVENT_LISTENER(removetrack);
 
-#if !ENABLE(OILPAN)
-    void clearOwner();
-#endif
     HTMLMediaElement* owner() const;
 
     void scheduleChangeEvent();
diff --git a/third_party/WebKit/Source/core/html/track/TrackBase.cpp b/third_party/WebKit/Source/core/html/track/TrackBase.cpp
index d4eb750e..7a2ce55f 100644
--- a/third_party/WebKit/Source/core/html/track/TrackBase.cpp
+++ b/third_party/WebKit/Source/core/html/track/TrackBase.cpp
@@ -52,9 +52,6 @@
 
 TrackBase::~TrackBase()
 {
-#if !ENABLE(OILPAN)
-    ASSERT(!m_mediaElement);
-#endif
 }
 
 Node* TrackBase::owner() const
diff --git a/third_party/WebKit/Source/core/html/track/TrackListBase.h b/third_party/WebKit/Source/core/html/track/TrackListBase.h
index aeba842..d849da6 100644
--- a/third_party/WebKit/Source/core/html/track/TrackListBase.h
+++ b/third_party/WebKit/Source/core/html/track/TrackListBase.h
@@ -23,10 +23,6 @@
 
     ~TrackListBase() override
     {
-#if !ENABLE(OILPAN)
-        ASSERT(m_tracks.isEmpty());
-        ASSERT(!m_mediaElement);
-#endif
     }
 
     unsigned length() const { return m_tracks.size(); }
@@ -59,14 +55,6 @@
         return nullptr;
     }
 
-#if !ENABLE(OILPAN)
-    void shutdown()
-    {
-        removeAll();
-        m_mediaElement = nullptr;
-    }
-#endif
-
     void add(T* track)
     {
         track->setMediaElement(m_mediaElement);
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
index 24154469..5b1bf91d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.cpp
@@ -365,6 +365,9 @@
 
     bool shouldClipOverflow = !styleRef().isOverflowVisible() && allowsOverflowClip();
     if (shouldClipOverflow != hasOverflowClip()) {
+        if (!shouldClipOverflow)
+            getScrollableArea()->invalidateAllStickyConstraints();
+
         // FIXME: This shouldn't be required if we tracked the visual overflow
         // generated by positioned children or self painting layers. crbug.com/345403
         for (LayoutObject* child = firstChild(); child; child = child->nextSibling())
@@ -840,8 +843,12 @@
     return childrenMarkedForRelayout;
 }
 
-void LayoutBlock::updateScrollInfoAfterLayout()
+void LayoutBlock::updateAfterLayout()
 {
+    invalidateStickyConstraints();
+
+    // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
+    // we overflow or not.
     if (hasOverflowClip()) {
         if (style()->isFlippedBlocksWritingMode()) {
             // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
@@ -1084,7 +1091,7 @@
 
     updateLayerTransformAfterLayout();
 
-    updateScrollInfoAfterLayout();
+    updateAfterLayout();
 
     clearNeedsLayout();
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlock.h b/third_party/WebKit/Source/core/layout/LayoutBlock.h
index ae8ca76..b6dc09146 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlock.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBlock.h
@@ -353,7 +353,7 @@
     static void startDelayUpdateScrollInfo();
     static bool finishDelayUpdateScrollInfo(SubtreeLayoutScope*, ScrollPositionMap*);
 
-    void updateScrollInfoAfterLayout();
+    void updateAfterLayout();
 
     void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override;
     void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
index a2bfab4..927e9aa 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.cpp
@@ -330,9 +330,7 @@
 
     updateLayerTransformAfterLayout();
 
-    // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
-    // we overflow or not.
-    updateScrollInfoAfterLayout();
+    updateAfterLayout();
 
     if (m_paintInvalidationLogicalTop != m_paintInvalidationLogicalBottom) {
         bool hasVisibleContent = style()->visibility() == VISIBLE;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index 9d8908a9..8b58376 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -282,8 +282,34 @@
     }
 
     if (FrameView *frameView = view()->frameView()) {
-        bool newStyleIsViewportConstained = style()->hasViewportConstrainedPosition();
-        bool oldStyleIsViewportConstrained = oldStyle && oldStyle->hasViewportConstrainedPosition();
+        bool newStyleIsViewportConstained = style()->position() == FixedPosition;
+        bool oldStyleIsViewportConstrained = oldStyle && oldStyle->position() == FixedPosition;
+        bool newStyleIsSticky = style()->position() == StickyPosition;
+        bool oldStyleIsSticky = oldStyle && oldStyle->position() == StickyPosition;
+
+        if (newStyleIsSticky != oldStyleIsSticky) {
+            if (newStyleIsSticky) {
+                frameView->addStickyPositionObject();
+                // During compositing inputs update we'll have the scroll
+                // ancestor without having to walk up the tree and can compute
+                // the sticky position constraints then.
+                if (layer())
+                    layer()->setNeedsCompositingInputsUpdate();
+            } else {
+                // This may get re-added to viewport constrained objects if the object went
+                // from sticky to fixed.
+                frameView->removeViewportConstrainedObject(this);
+                frameView->removeStickyPositionObject();
+
+                // Remove sticky constraints for this layer.
+                if (layer()) {
+                    DisableCompositingQueryAsserts disabler;
+                    if (const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer())
+                        ancestorOverflowLayer->getScrollableArea()->invalidateStickyConstraintsFor(layer());
+                }
+            }
+        }
+
         if (newStyleIsViewportConstained != oldStyleIsViewportConstrained) {
             if (newStyleIsViewportConstained && layer())
                 frameView->addViewportConstrainedObject(this);
@@ -293,6 +319,19 @@
     }
 }
 
+void LayoutBoxModelObject::invalidateStickyConstraints()
+{
+    if (!layer())
+        return;
+
+    // This intentionally uses the stale ancestor overflow layer compositing
+    // input as if we have saved constraints for this layer they were saved
+    // in the previous frame.
+    DisableCompositingQueryAsserts disabler;
+    if (const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer())
+        ancestorOverflowLayer->getScrollableArea()->invalidateAllStickyConstraints();
+}
+
 void LayoutBoxModelObject::createLayer(PaintLayerType type)
 {
     ASSERT(!m_layer);
@@ -598,6 +637,134 @@
     return offset;
 }
 
+void LayoutBoxModelObject::updateStickyPositionConstraints() const
+{
+    // TODO(flackr): This method is reasonably complicated and should have some direct unit testing.
+    const FloatSize constrainingSize = computeStickyConstrainingRect().size();
+
+    PaintLayerScrollableArea* scrollableArea = layer()->ancestorOverflowLayer()->getScrollableArea();
+    StickyPositionScrollingConstraints constraints;
+    FloatSize skippedContainersOffset;
+    LayoutBlock* containingBlock = this->containingBlock();
+    // Skip anonymous containing blocks.
+    while (containingBlock->isAnonymous()) {
+        skippedContainersOffset += toFloatSize(FloatPoint(containingBlock->frameRect().location()));
+        containingBlock = containingBlock->containingBlock();
+    }
+    LayoutBox* scrollAncestor = layer()->ancestorOverflowLayer()->isRootLayer() ? nullptr : toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject());
+
+    LayoutRect containerContentRect = containingBlock->contentBoxRect();
+    LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
+
+    // Sticky positioned element ignore any override logical width on the containing block (as they don't call
+    // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine.
+    // Compute the container-relative area within which the sticky element is allowed to move.
+    containerContentRect.contractEdges(
+        minimumValueForLength(style()->marginTop(), maxWidth),
+        minimumValueForLength(style()->marginRight(), maxWidth),
+        minimumValueForLength(style()->marginBottom(), maxWidth),
+        minimumValueForLength(style()->marginLeft(), maxWidth));
+
+    // Map to the scroll ancestor.
+    constraints.setScrollContainerRelativeContainingBlockRect(containingBlock->localToAncestorQuad(FloatRect(containerContentRect), scrollAncestor).boundingBox());
+
+    FloatRect stickyBoxRect = isLayoutInline()
+        ? FloatRect(toLayoutInline(this)->linesBoundingBox())
+        : FloatRect(toLayoutBox(this)->frameRect());
+    FloatRect flippedStickyBoxRect = stickyBoxRect;
+    containingBlock->flipForWritingMode(flippedStickyBoxRect);
+    FloatPoint stickyLocation = flippedStickyBoxRect.location() + skippedContainersOffset;
+
+    // TODO(flackr): Unfortunate to call localToAncestorQuad again, but we can't just offset from the previously computed rect if there are transforms.
+    // Map to the scroll ancestor.
+    FloatRect scrollContainerRelativeContainerFrame = containingBlock->localToAncestorQuad(FloatRect(FloatPoint(), FloatSize(containingBlock->size())), scrollAncestor).boundingBox();
+
+    // If the containing block is our scroll ancestor, its location will not include the scroll offset which we need to include as
+    // part of the sticky box rect so we include it here.
+    if (containingBlock->hasOverflowClip()) {
+        FloatSize scrollOffset(toFloatSize(containingBlock->layer()->getScrollableArea()->adjustedScrollOffset()));
+        stickyLocation -= scrollOffset;
+    }
+
+    constraints.setScrollContainerRelativeStickyBoxRect(FloatRect(scrollContainerRelativeContainerFrame.location() + toFloatSize(stickyLocation), flippedStickyBoxRect.size()));
+
+    // We skip the right or top sticky offset if there is not enough space to honor both the left/right or top/bottom offsets.
+    LayoutUnit horizontalOffsets = minimumValueForLength(style()->right(), LayoutUnit(constrainingSize.width())) +
+        minimumValueForLength(style()->left(), LayoutUnit(constrainingSize.width()));
+    bool skipRight = false;
+    bool skipLeft = false;
+    if (!style()->left().isAuto() && !style()->right().isAuto()) {
+        if (horizontalOffsets > containerContentRect.width()
+            || horizontalOffsets + containerContentRect.width() > constrainingSize.width()) {
+            skipRight = style()->isLeftToRightDirection();
+            skipLeft = !skipRight;
+        }
+    }
+
+    if (!style()->left().isAuto() && !skipLeft) {
+        constraints.setLeftOffset(minimumValueForLength(style()->left(), LayoutUnit(constrainingSize.width())));
+        constraints.addAnchorEdge(StickyPositionScrollingConstraints::AnchorEdgeLeft);
+    }
+
+    if (!style()->right().isAuto() && !skipRight) {
+        constraints.setRightOffset(minimumValueForLength(style()->right(), LayoutUnit(constrainingSize.width())));
+        constraints.addAnchorEdge(StickyPositionScrollingConstraints::AnchorEdgeRight);
+    }
+
+    bool skipBottom = false;
+    // TODO(flackr): Exclude top or bottom edge offset depending on the writing mode when related
+    // sections are fixed in spec: http://lists.w3.org/Archives/Public/www-style/2014May/0286.html
+    LayoutUnit verticalOffsets = minimumValueForLength(style()->top(), LayoutUnit(constrainingSize.height())) +
+        minimumValueForLength(style()->bottom(), LayoutUnit(constrainingSize.height()));
+    if (!style()->top().isAuto() && !style()->bottom().isAuto()) {
+        if (verticalOffsets > containerContentRect.height()
+            || verticalOffsets + containerContentRect.height() > constrainingSize.height()) {
+            skipBottom = true;
+        }
+    }
+
+    if (!style()->top().isAuto()) {
+        constraints.setTopOffset(minimumValueForLength(style()->top(), LayoutUnit(constrainingSize.height())));
+        constraints.addAnchorEdge(StickyPositionScrollingConstraints::AnchorEdgeTop);
+    }
+
+    if (!style()->bottom().isAuto() && !skipBottom) {
+        constraints.setBottomOffset(minimumValueForLength(style()->bottom(), LayoutUnit(constrainingSize.height())));
+        constraints.addAnchorEdge(StickyPositionScrollingConstraints::AnchorEdgeBottom);
+    }
+    scrollableArea->stickyConstraintsMap().set(layer(), constraints);
+}
+
+FloatRect LayoutBoxModelObject::computeStickyConstrainingRect() const
+{
+    if (layer()->ancestorOverflowLayer()->isRootLayer())
+        return view()->frameView()->visibleContentRect();
+
+    LayoutBox* enclosingClippingBox = toLayoutBox(layer()->ancestorOverflowLayer()->layoutObject());
+    FloatRect constrainingRect;
+    constrainingRect = FloatRect(enclosingClippingBox->overflowClipRect(LayoutPoint()));
+    constrainingRect.move(enclosingClippingBox->paddingLeft(), enclosingClippingBox->paddingTop());
+    constrainingRect.contract(FloatSize(enclosingClippingBox->paddingLeft() + enclosingClippingBox->paddingRight(),
+        enclosingClippingBox->paddingTop() + enclosingClippingBox->paddingBottom()));
+    return constrainingRect;
+}
+
+LayoutSize LayoutBoxModelObject::stickyPositionOffset() const
+{
+    const PaintLayer* ancestorOverflowLayer = layer()->ancestorOverflowLayer();
+    // TODO: Force compositing input update if we ask for offset before compositing inputs have been computed?
+    if (!ancestorOverflowLayer)
+        return LayoutSize();
+    FloatRect constrainingRect = computeStickyConstrainingRect();
+    PaintLayerScrollableArea* scrollableArea = ancestorOverflowLayer->getScrollableArea();
+
+    // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms).
+    // TODO: Force compositing input update if we ask for offset with stale compositing inputs.
+    if (!scrollableArea->stickyConstraintsMap().contains(layer()))
+        return LayoutSize();
+    return LayoutSize(scrollableArea->stickyConstraintsMap().get(layer()).computeStickyOffset(constrainingRect));
+}
+
 LayoutPoint LayoutBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const
 {
     // If the element is the HTML body element or doesn't have a parent
@@ -620,7 +787,7 @@
             referencePoint.move(-toLayoutBox(offsetParent)->borderLeft(), -toLayoutBox(offsetParent)->borderTop());
         if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
             if (isInFlowPositioned())
-                referencePoint.move(relativePositionOffset());
+                referencePoint.move(offsetForInFlowPosition());
 
             LayoutObject* current;
             for (current = parent(); current != offsetParent && current->parent(); current = current->parent()) {
@@ -642,7 +809,13 @@
 
 LayoutSize LayoutBoxModelObject::offsetForInFlowPosition() const
 {
-    return isRelPositioned() ? relativePositionOffset() : LayoutSize();
+    if (isRelPositioned())
+        return relativePositionOffset();
+
+    if (isStickyPositioned())
+        return stickyPositionOffset();
+
+    return LayoutSize();
 }
 
 LayoutUnit LayoutBoxModelObject::offsetLeft() const
@@ -881,10 +1054,10 @@
         TransformationMatrix t;
         getTransformFromContainer(container, containerOffset, t);
         t.translateRight(adjustmentForSkippedAncestor.width().toFloat(), adjustmentForSkippedAncestor.height().toFloat());
-        geometryMap.push(this, t, flags);
+        geometryMap.push(this, t, flags, LayoutSize());
     } else {
         containerOffset += adjustmentForSkippedAncestor;
-        geometryMap.push(this, containerOffset, flags);
+        geometryMap.push(this, containerOffset, flags, LayoutSize());
     }
 
     return ancestorSkipped ? ancestorToStopAt : container;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index bd836e9..39f95eb 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -26,6 +26,7 @@
 
 #include "core/CoreExport.h"
 #include "core/layout/LayoutObject.h"
+#include "core/page/scrolling/StickyPositionScrollingConstraints.h"
 #include "core/style/ShadowData.h"
 #include "platform/geometry/LayoutRect.h"
 
@@ -64,6 +65,15 @@
 
 class InlineFlowBox;
 
+struct LayoutBoxModelObjectRareData {
+    WTF_MAKE_NONCOPYABLE(LayoutBoxModelObjectRareData);
+    USING_FAST_MALLOC(LayoutBoxModelObjectRareData);
+public:
+    LayoutBoxModelObjectRareData() {}
+
+    StickyPositionScrollingConstraints m_stickyPositionScrollingConstraints;
+};
+
 // This class is the base class for all CSS objects.
 //
 // All CSS objects follow the box model object. See THE BOX MODEL section in
@@ -141,6 +151,12 @@
     LayoutSize relativePositionOffset() const;
     LayoutSize relativePositionLogicalOffset() const { return style()->isHorizontalWritingMode() ? relativePositionOffset() : relativePositionOffset().transposedSize(); }
 
+    // Populates StickyPositionConstraints, setting the sticky box rect, containing block rect and updating
+    // the constraint offsets according to the available space.
+    FloatRect computeStickyConstrainingRect() const;
+    void updateStickyPositionConstraints() const;
+    LayoutSize stickyPositionOffset() const;
+
     LayoutSize offsetForInFlowPosition() const;
 
     // IE extensions. Used to calculate offsetWidth/Height.  Overridden by inlines (LayoutFlow)
@@ -330,6 +346,8 @@
     void styleWillChange(StyleDifference, const ComputedStyle& newStyle) override;
     void styleDidChange(StyleDifference, const ComputedStyle* oldStyle) override;
 
+    void invalidateStickyConstraints();
+
 public:
     // These functions are only used internally to manipulate the layout tree structure via remove/insert/appendChildNode.
     // Since they are typically called only to move objects around within anonymous blocks (which only have layers in
@@ -361,9 +379,18 @@
     LayoutUnit computedCSSPadding(const Length&) const;
     bool isBoxModelObject() const final { return true; }
 
+    LayoutBoxModelObjectRareData& ensureRareData()
+    {
+        if (!m_rareData)
+            m_rareData = adoptPtr(new LayoutBoxModelObjectRareData());
+        return *m_rareData.get();
+    }
+
     // The PaintLayer associated with this object.
     // |m_layer| can be nullptr depending on the return value of layerTypeRequired().
     OwnPtr<PaintLayer> m_layer;
+
+    OwnPtr<LayoutBoxModelObjectRareData> m_rareData;
 };
 
 DEFINE_LAYOUT_OBJECT_TYPE_CASTS(LayoutBoxModelObject, isBoxModelObject());
diff --git a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
index e8b9413..ed3942e 100644
--- a/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutDeprecatedFlexibleBox.cpp
@@ -261,7 +261,7 @@
     }
 
     updateLayerTransformAfterLayout();
-    updateScrollInfoAfterLayout();
+    updateAfterLayout();
 
     if (view()->layoutState()->pageLogicalHeight())
         setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(*this, logicalTop()));
diff --git a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
index 816f4f36..a781e688 100644
--- a/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutFlexibleBox.cpp
@@ -309,7 +309,7 @@
 
     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
     // we overflow or not.
-    updateScrollInfoAfterLayout();
+    updateAfterLayout();
 
     clearNeedsLayout();
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutGeometryMapStep.h b/third_party/WebKit/Source/core/layout/LayoutGeometryMapStep.h
index 85a7efb..6b4350d 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGeometryMapStep.h
+++ b/third_party/WebKit/Source/core/layout/LayoutGeometryMapStep.h
@@ -51,6 +51,7 @@
         : m_layoutObject(o.m_layoutObject)
         , m_offset(o.m_offset)
         , m_offsetForFixedPosition(o.m_offsetForFixedPosition)
+        , m_offsetForStickyPosition(o.m_offsetForStickyPosition)
         , m_flags(o.m_flags)
     {
         ASSERT(!o.m_transform);
@@ -63,7 +64,10 @@
     const LayoutObject* m_layoutObject;
     LayoutSize m_offset;
     OwnPtr<TransformationMatrix> m_transform; // Includes offset if non-null.
+    // If m_offsetForFixedPosition could only apply to the fixed position steps, we may be able to merge
+    // with m_offsetForStickyPosition and simplify mapping.
     LayoutSize m_offsetForFixedPosition;
+    LayoutSize m_offsetForStickyPosition;
     GeometryInfoFlags m_flags;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index c289e73..8fc563f3 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -404,7 +404,7 @@
     }
 
     updateLayerTransformAfterLayout();
-    updateScrollInfoAfterLayout();
+    updateAfterLayout();
 
     clearNeedsLayout();
 }
diff --git a/third_party/WebKit/Source/core/layout/LayoutTable.cpp b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
index bbcf8f5..6d1bffb 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTable.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTable.cpp
@@ -573,7 +573,7 @@
         invalidateCollapsedBorders();
 
         computeOverflow(clientLogicalBottom());
-        updateScrollInfoAfterLayout();
+        updateAfterLayout();
     }
 
     // FIXME: This value isn't the intrinsic content logical height, but we need
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableRow.h b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
index d167a9a..9f7d6694 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableRow.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableRow.h
@@ -145,7 +145,7 @@
 
     PaintLayerType layerTypeRequired() const override
     {
-        if (hasTransformRelatedProperty() || hasHiddenBackface() || hasClipPath() || createsGroup() || style()->shouldCompositeForCurrentAnimations() || style()->hasCompositorProxy())
+        if (hasTransformRelatedProperty() || hasHiddenBackface() || hasClipPath() || createsGroup() || style()->shouldCompositeForCurrentAnimations() || isStickyPositioned() || style()->hasCompositorProxy())
             return NormalPaintLayer;
 
         if (hasOverflowClip())
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
index f100b65..c823e20 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.cpp
@@ -4,7 +4,9 @@
 
 #include "core/layout/compositing/CompositingInputsUpdater.h"
 
+#include "core/frame/FrameView.h"
 #include "core/layout/LayoutBlock.h"
+#include "core/layout/LayoutView.h"
 #include "core/layout/compositing/CompositedLayerMapping.h"
 #include "core/layout/compositing/PaintLayerCompositor.h"
 #include "core/paint/PaintLayer.h"
@@ -97,6 +99,28 @@
     if (!layer->childNeedsCompositingInputsUpdate() && updateType != ForceUpdate)
         return;
 
+    const PaintLayer* previousOverflowLayer = layer->ancestorOverflowLayer();
+    layer->updateAncestorOverflowLayer(info.lastOverflowClipLayer);
+    if (info.lastOverflowClipLayer && layer->needsCompositingInputsUpdate() && layer->layoutObject()->style()->position() == StickyPosition) {
+        if (info.lastOverflowClipLayer != previousOverflowLayer) {
+            // Old ancestor scroller should no longer have these constraints.
+            ASSERT(!previousOverflowLayer || !previousOverflowLayer->getScrollableArea()->stickyConstraintsMap().contains(layer));
+
+            if (info.lastOverflowClipLayer->isRootLayer())
+                layer->layoutObject()->view()->frameView()->addViewportConstrainedObject(layer->layoutObject());
+            else if (previousOverflowLayer && previousOverflowLayer->isRootLayer())
+                layer->layoutObject()->view()->frameView()->removeViewportConstrainedObject(layer->layoutObject());
+        }
+        layer->layoutObject()->updateStickyPositionConstraints();
+
+        // Sticky position constraints and ancestor overflow scroller affect
+        // the sticky layer position, so we need to update it again here.
+        // TODO(flackr): This should be refactored in the future to be clearer
+        // (i.e. update layer position and ancestor inputs updates in the
+        // same walk)
+        layer->updateLayerPosition();
+    }
+
     m_geometryMap.pushMappingsToAncestor(layer, layer->parent());
 
     if (layer->hasCompositedLayerMapping())
@@ -163,6 +187,9 @@
     if (layer->stackingNode()->isStackingContext())
         info.ancestorStackingContext = layer;
 
+    if (layer->isRootLayer() || layer->layoutObject()->hasOverflowClip())
+        info.lastOverflowClipLayer = layer;
+
     if (layer->scrollsOverflow())
         info.lastScrollingAncestor = layer;
 
diff --git a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h
index d182c926..1723c8d2 100644
--- a/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h
+++ b/third_party/WebKit/Source/core/layout/compositing/CompositingInputsUpdater.h
@@ -34,6 +34,7 @@
         AncestorInfo()
             : ancestorStackingContext(nullptr)
             , enclosingCompositedLayer(nullptr)
+            , lastOverflowClipLayer(nullptr)
             , lastScrollingAncestor(nullptr)
             , hasAncestorWithClipRelatedProperty(false)
             , hasAncestorWithClipPath(false)
@@ -42,6 +43,7 @@
 
         PaintLayer* ancestorStackingContext;
         PaintLayer* enclosingCompositedLayer;
+        PaintLayer* lastOverflowClipLayer;
         // Notice that lastScrollingAncestor isn't the same thing as
         // ancestorScrollingLayer. The former is just the nearest scrolling
         // along the PaintLayer::parent() chain. The latter is the layer that
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 35e37d3..7e5ceb89 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -937,7 +937,8 @@
 
     for (const LayoutObject* layoutObject : *viewportConstrainedObjects) {
         ASSERT(layoutObject->isBoxModelObject() && layoutObject->hasLayer());
-        ASSERT(layoutObject->style()->position() == FixedPosition);
+        ASSERT(layoutObject->style()->position() == FixedPosition
+            || layoutObject->style()->position() == StickyPosition);
         PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer();
 
         // Whether the Layer scrolls with the viewport is a tree-depenent
@@ -986,6 +987,8 @@
 
         if (frameView->hasBackgroundAttachmentFixedObjects())
             reasons |= MainThreadScrollingReason::kHasBackgroundAttachmentFixedObjects;
+        if (frameView->hasStickyPositionObjects())
+            reasons |= MainThreadScrollingReason::kHasStickyPositionObjects;
         FrameView::ScrollingReasons scrollingReasons = frameView->getScrollingReasons();
         const bool mayBeScrolledByInput = (scrollingReasons == FrameView::Scrollable);
         const bool mayBeScrolledByScript = mayBeScrolledByInput || (scrollingReasons ==
@@ -1011,6 +1014,8 @@
         stringBuilder.appendLiteral("Has background-attachment:fixed, ");
     if (reasons & MainThreadScrollingReason::kHasNonLayerViewportConstrainedObjects)
         stringBuilder.appendLiteral("Has non-layer viewport-constrained objects, ");
+    if (reasons & MainThreadScrollingReason::kHasStickyPositionObjects)
+        stringBuilder.appendLiteral("Has sticky position objects, ");
     if (reasons & MainThreadScrollingReason::kThreadedScrollingDisabled)
         stringBuilder.appendLiteral("Threaded scrolling is disabled, ");
     if (reasons & MainThreadScrollingReason::kAnimatingScrollOnMainThread)
diff --git a/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.cpp b/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.cpp
new file mode 100644
index 0000000..1d4b07e
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.cpp
@@ -0,0 +1,56 @@
+// 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 "core/page/scrolling/StickyPositionScrollingConstraints.h"
+
+namespace blink {
+
+FloatSize StickyPositionScrollingConstraints::computeStickyOffset(const FloatRect& viewportRect) const
+{
+    FloatRect boxRect = m_scrollContainerRelativeStickyBoxRect;
+
+    if (hasAnchorEdge(AnchorEdgeRight)) {
+        float rightLimit = viewportRect.maxX() - m_rightOffset;
+        float rightDelta = std::min<float>(0, rightLimit - m_scrollContainerRelativeStickyBoxRect.maxX());
+        float availableSpace = std::min<float>(0, m_scrollContainerRelativeContainingBlockRect.x() - m_scrollContainerRelativeStickyBoxRect.x());
+        if (rightDelta < availableSpace)
+            rightDelta = availableSpace;
+
+        boxRect.move(rightDelta, 0);
+    }
+
+    if (hasAnchorEdge(AnchorEdgeLeft)) {
+        float leftLimit = viewportRect.x() + m_leftOffset;
+        float leftDelta = std::max<float>(0, leftLimit - m_scrollContainerRelativeStickyBoxRect.x());
+        float availableSpace = std::max<float>(0, m_scrollContainerRelativeContainingBlockRect.maxX() - m_scrollContainerRelativeStickyBoxRect.maxX());
+        if (leftDelta > availableSpace)
+            leftDelta = availableSpace;
+
+        boxRect.move(leftDelta, 0);
+    }
+
+    if (hasAnchorEdge(AnchorEdgeBottom)) {
+        float bottomLimit = viewportRect.maxY() - m_bottomOffset;
+        float bottomDelta = std::min<float>(0, bottomLimit - m_scrollContainerRelativeStickyBoxRect.maxY());
+        float availableSpace = std::min<float>(0, m_scrollContainerRelativeContainingBlockRect.y() - m_scrollContainerRelativeStickyBoxRect.y());
+        if (bottomDelta < availableSpace)
+            bottomDelta = availableSpace;
+
+        boxRect.move(0, bottomDelta);
+    }
+
+    if (hasAnchorEdge(AnchorEdgeTop)) {
+        float topLimit = viewportRect.y() + m_topOffset;
+        float topDelta = std::max<float>(0, topLimit - m_scrollContainerRelativeStickyBoxRect.y());
+        float availableSpace = std::max<float>(0, m_scrollContainerRelativeContainingBlockRect.maxY() - m_scrollContainerRelativeStickyBoxRect.maxY());
+        if (topDelta > availableSpace)
+            topDelta = availableSpace;
+
+        boxRect.move(0, topDelta);
+    }
+
+    return boxRect.location() - m_scrollContainerRelativeStickyBoxRect.location();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.h b/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.h
new file mode 100644
index 0000000..e9fd95b
--- /dev/null
+++ b/third_party/WebKit/Source/core/page/scrolling/StickyPositionScrollingConstraints.h
@@ -0,0 +1,85 @@
+// 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 StickyPositionScrollingConstraints_h
+#define StickyPositionScrollingConstraints_h
+
+#include "platform/geometry/FloatRect.h"
+
+namespace blink {
+
+class StickyPositionScrollingConstraints final {
+public:
+    enum AnchorEdgeFlags {
+        AnchorEdgeLeft = 1 << 0,
+        AnchorEdgeRight = 1 << 1,
+        AnchorEdgeTop = 1 << 2,
+        AnchorEdgeBottom = 1 << 3
+    };
+    typedef unsigned AnchorEdges;
+
+    StickyPositionScrollingConstraints()
+        : m_anchorEdges(0)
+        , m_leftOffset(0)
+        , m_rightOffset(0)
+        , m_topOffset(0)
+        , m_bottomOffset(0)
+    { }
+
+    StickyPositionScrollingConstraints(const StickyPositionScrollingConstraints& other)
+        : m_anchorEdges(other.m_anchorEdges)
+        , m_leftOffset(other.m_leftOffset)
+        , m_rightOffset(other.m_rightOffset)
+        , m_topOffset(other.m_topOffset)
+        , m_bottomOffset(other.m_bottomOffset)
+        , m_scrollContainerRelativeContainingBlockRect(other.m_scrollContainerRelativeContainingBlockRect)
+        , m_scrollContainerRelativeStickyBoxRect(other.m_scrollContainerRelativeStickyBoxRect)
+    { }
+
+    FloatSize computeStickyOffset(const FloatRect& viewportRect) const;
+
+    AnchorEdges anchorEdges() const { return m_anchorEdges; }
+    bool hasAnchorEdge(AnchorEdgeFlags flag) const { return m_anchorEdges & flag; }
+    void addAnchorEdge(AnchorEdgeFlags edgeFlag) { m_anchorEdges |= edgeFlag; }
+    void setAnchorEdges(AnchorEdges edges) { m_anchorEdges = edges; }
+
+    float leftOffset() const { return m_leftOffset; }
+    float rightOffset() const { return m_rightOffset; }
+    float topOffset() const { return m_topOffset; }
+    float bottomOffset() const { return m_bottomOffset; }
+
+    void setLeftOffset(float offset) { m_leftOffset = offset; }
+    void setRightOffset(float offset) { m_rightOffset = offset; }
+    void setTopOffset(float offset) { m_topOffset = offset; }
+    void setBottomOffset(float offset) { m_bottomOffset = offset; }
+
+    void setScrollContainerRelativeContainingBlockRect(const FloatRect& rect) { m_scrollContainerRelativeContainingBlockRect = rect; }
+
+    void setScrollContainerRelativeStickyBoxRect(const FloatRect& rect) { m_scrollContainerRelativeStickyBoxRect = rect; }
+
+    bool operator==(const StickyPositionScrollingConstraints& other) const
+    {
+        return m_leftOffset == other.m_leftOffset
+            && m_rightOffset == other.m_rightOffset
+            && m_topOffset == other.m_topOffset
+            && m_bottomOffset == other.m_bottomOffset
+            && m_scrollContainerRelativeContainingBlockRect == other.m_scrollContainerRelativeContainingBlockRect
+            && m_scrollContainerRelativeStickyBoxRect == other.m_scrollContainerRelativeStickyBoxRect;
+    }
+
+    bool operator!=(const StickyPositionScrollingConstraints& other) const { return !(*this == other); }
+
+private:
+    AnchorEdges m_anchorEdges;
+    float m_leftOffset;
+    float m_rightOffset;
+    float m_topOffset;
+    float m_bottomOffset;
+    FloatRect m_scrollContainerRelativeContainingBlockRect;
+    FloatRect m_scrollContainerRelativeStickyBoxRect;
+};
+
+} // namespace blink
+
+#endif // StickyPositionScrollingConstraints_h
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 771be03..832ee11 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -99,7 +99,7 @@
 
 struct SameSizeAsPaintLayer : DisplayItemClient {
     int bitFields;
-    void* pointers[9];
+    void* pointers[10];
     LayoutUnit layoutUnits[4];
     IntSize size;
     Persistent<PaintLayerScrollableArea> scrollableArea;
@@ -172,6 +172,7 @@
     , m_last(0)
     , m_staticInlinePosition(0)
     , m_staticBlockPosition(0)
+    , m_ancestorOverflowLayer(nullptr)
 {
     updateStackingNode();
 
@@ -349,7 +350,8 @@
 
 bool PaintLayer::scrollsWithViewport() const
 {
-    return layoutObject()->style()->position() == FixedPosition && layoutObject()->containerForFixedPosition() == layoutObject()->view();
+    return (layoutObject()->style()->position() == FixedPosition && layoutObject()->containerForFixedPosition() == layoutObject()->view())
+        || (layoutObject()->style()->position() == StickyPosition && !ancestorScrollingLayer());
 }
 
 bool PaintLayer::scrollsWithRespectTo(const PaintLayer* other) const
@@ -747,7 +749,7 @@
     return has3DTransform();
 }
 
-bool PaintLayer::updateLayerPosition()
+void PaintLayer::updateLayerPosition()
 {
     LayoutPoint localPoint;
     LayoutPoint inlineBoundingBoxOffset; // We don't put this into the Layer x/y for inlines, so we need to subtract it out when done.
@@ -798,10 +800,8 @@
         localPoint -= scrollOffset;
     }
 
-    bool positionOrOffsetChanged = false;
     if (layoutObject()->isInFlowPositioned()) {
         LayoutSize newOffset = layoutObject()->offsetForInFlowPosition();
-        positionOrOffsetChanged = newOffset != offsetForInFlowPosition();
         if (m_rareData || !newOffset.isZero())
             ensureRareData().offsetForInFlowPosition = newOffset;
         localPoint.move(newOffset);
@@ -813,7 +813,6 @@
     localPoint.moveBy(-inlineBoundingBoxOffset);
 
     if (m_location != localPoint) {
-        positionOrOffsetChanged = true;
         setNeedsRepaint();
     }
     m_location = localPoint;
@@ -821,7 +820,6 @@
 #if ENABLE(ASSERT)
     m_needsPositionUpdate = false;
 #endif
-    return positionOrOffsetChanged;
 }
 
 TransformationMatrix PaintLayer::perspectiveTransform() const
@@ -1182,6 +1180,9 @@
 
     child->m_parent = this;
 
+    // The ancestor overflow layer is calculated during compositing inputs update and should not be set yet.
+    ASSERT(!child->ancestorOverflowLayer());
+
     setNeedsCompositingInputsUpdate();
 
     if (!child->stackingNode()->isStacked() && !layoutObject()->documentBeingDestroyed())
@@ -1236,6 +1237,10 @@
     oldChild->setNextSibling(0);
     oldChild->m_parent = 0;
 
+    // Remove any ancestor overflow layers which descended into the removed child.
+    if (oldChild->ancestorOverflowLayer())
+        oldChild->removeAncestorOverflowLayer(oldChild->ancestorOverflowLayer());
+
     dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
 
     oldChild->updateDescendantDependentFlags();
@@ -2686,6 +2691,23 @@
     return *rareData.filterInfo;
 }
 
+void PaintLayer::removeAncestorOverflowLayer(const PaintLayer* removedLayer)
+{
+    // If the current ancestor overflow layer does not match the removed layer
+    // the ancestor overflow layer has changed so we can stop searching.
+    if (ancestorOverflowLayer() && ancestorOverflowLayer() != removedLayer)
+        return;
+
+    if (ancestorOverflowLayer())
+        ancestorOverflowLayer()->getScrollableArea()->invalidateStickyConstraintsFor(this);
+    updateAncestorOverflowLayer(nullptr);
+    PaintLayer* current = m_first;
+    while (current) {
+        current->removeAncestorOverflowLayer(removedLayer);
+        current = current->nextSibling();
+    }
+}
+
 void PaintLayer::updateOrRemoveFilterClients()
 {
     const auto& filter = layoutObject()->style()->filter();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index 72920fc..53bdcbc6 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -271,6 +271,8 @@
     // Allows updates of layer content without invalidating paint.
     void contentChanged(ContentChangeType);
 
+    void updateLayerPosition();
+
     void updateLayerPositionsAfterLayout();
     void updateLayerPositionsAfterOverflowScroll(const DoubleSize& scrollDelta);
 
@@ -542,6 +544,10 @@
         const PaintLayer* opacityAncestor;
         const PaintLayer* transformAncestor;
         const PaintLayer* filterAncestor;
+
+        // The fist ancestor which can scroll. This is a subset of the
+        // ancestorOverflowLayer chain where the scrolling layer is visible and
+        // has a larger scroll content than its bounds.
         const PaintLayer* ancestorScrollingLayer;
         const PaintLayer* nearestFixedPositionLayer;
 
@@ -571,6 +577,7 @@
         return m_needsDescendantDependentCompositingInputsUpdate;
     }
 
+    void updateAncestorOverflowLayer(const PaintLayer* ancestorOverflowLayer) { m_ancestorOverflowLayer = ancestorOverflowLayer; }
     void updateAncestorDependentCompositingInputs(const AncestorDependentCompositingInputs&, const RareAncestorDependentCompositingInputs&, bool hasAncestorWithClipPath);
     void updateDescendantDependentCompositingInputs(bool hasDescendantWithClipPath, bool hasNonIsolatedDescendantWithBlendMode);
     void didUpdateCompositingInputs();
@@ -580,6 +587,7 @@
     const PaintLayer* transformAncestor() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_rareAncestorDependentCompositingInputs ? m_rareAncestorDependentCompositingInputs->transformAncestor : nullptr; }
     const PaintLayer* filterAncestor() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_rareAncestorDependentCompositingInputs ? m_rareAncestorDependentCompositingInputs->filterAncestor : nullptr; }
     const LayoutObject* clippingContainer() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_ancestorDependentCompositingInputs.clippingContainer; }
+    const PaintLayer* ancestorOverflowLayer() const { return m_ancestorOverflowLayer; }
     const PaintLayer* ancestorScrollingLayer() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_rareAncestorDependentCompositingInputs ? m_rareAncestorDependentCompositingInputs->ancestorScrollingLayer : nullptr; }
     const PaintLayer* nearestFixedPositionLayer() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_rareAncestorDependentCompositingInputs ? m_rareAncestorDependentCompositingInputs->nearestFixedPositionLayer : nullptr; }
     const PaintLayer* scrollParent() const { ASSERT(!m_needsAncestorDependentCompositingInputsUpdate); return m_rareAncestorDependentCompositingInputs ? m_rareAncestorDependentCompositingInputs->scrollParent : nullptr; }
@@ -698,9 +706,6 @@
 
     void dirtyAncestorChainHasSelfPaintingLayerDescendantStatus();
 
-    // Returns true if the position changed.
-    bool updateLayerPosition();
-
     void updateLayerPositionRecursive();
     void updateLayerPositionsAfterScrollRecursive(const DoubleSize& scrollDelta, bool paintInvalidationContainerWasScrolled);
 
@@ -757,6 +762,8 @@
     // Both updates the status, and returns true if descendants of this have 3d.
     bool update3DTransformedDescendantStatus();
 
+    void removeAncestorOverflowLayer(const PaintLayer* removedLayer);
+
     void updateOrRemoveFilterClients();
 
     void updatePaginationRecursive(bool needsPaginationUpdate = false);
@@ -861,6 +868,9 @@
     LayoutUnit m_staticInlinePosition;
     LayoutUnit m_staticBlockPosition;
 
+    // The first ancestor having a non visible overflow.
+    const PaintLayer* m_ancestorOverflowLayer;
+
     AncestorDependentCompositingInputs m_ancestorDependentCompositingInputs;
     OwnPtr<RareAncestorDependentCompositingInputs> m_rareAncestorDependentCompositingInputs;
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
index 5cbad74c..d30b32f1 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.cpp
@@ -1235,6 +1235,26 @@
     }
 }
 
+void PaintLayerScrollableArea::invalidateAllStickyConstraints()
+{
+    if (PaintLayerScrollableAreaRareData* d = rareData()) {
+        for (PaintLayer* stickyLayer : d->m_stickyConstraintsMap.keys()) {
+            if (stickyLayer->layoutObject()->style()->position() == StickyPosition)
+                stickyLayer->setNeedsCompositingInputsUpdate();
+        }
+        d->m_stickyConstraintsMap.clear();
+    }
+}
+
+void PaintLayerScrollableArea::invalidateStickyConstraintsFor(PaintLayer* layer, bool needsCompositingUpdate)
+{
+    if (PaintLayerScrollableAreaRareData* d = rareData()) {
+        d->m_stickyConstraintsMap.remove(layer);
+        if (needsCompositingUpdate && layer->layoutObject()->style()->position() == StickyPosition)
+            layer->setNeedsCompositingInputsUpdate();
+    }
+}
+
 IntSize PaintLayerScrollableArea::offsetFromResizeCorner(const IntPoint& absolutePoint) const
 {
     // Currently the resize corner is either the bottom right corner or the bottom left corner.
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
index ba390ad0..8ae8e33 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -63,6 +63,17 @@
 class PaintLayer;
 class LayoutScrollbarPart;
 
+typedef WTF::HashMap<PaintLayer*, StickyPositionScrollingConstraints> StickyConstraintsMap;
+
+struct PaintLayerScrollableAreaRareData {
+    WTF_MAKE_NONCOPYABLE(PaintLayerScrollableAreaRareData);
+    USING_FAST_MALLOC(PaintLayerScrollableAreaRareData);
+public:
+    PaintLayerScrollableAreaRareData() {}
+
+    StickyConstraintsMap m_stickyConstraintsMap;
+};
+
 // PaintLayerScrollableArea represents the scrollable area of a LayoutBox.
 //
 // To be scrollable, an element requires ‘overflow’ != visible. Note that this
@@ -340,6 +351,10 @@
     bool shouldRebuildVerticalScrollbarLayer() const { return m_rebuildVerticalScrollbarLayer; }
     void resetRebuildScrollbarLayerFlags();
 
+    StickyConstraintsMap& stickyConstraintsMap() { return ensureRareData().m_stickyConstraintsMap; }
+    void invalidateAllStickyConstraints();
+    void invalidateStickyConstraintsFor(PaintLayer*, bool needsCompositingUpdate = true);
+
     DECLARE_VIRTUAL_TRACE();
 
 private:
@@ -375,6 +390,18 @@
 
     void updateCompositingLayersAfterScroll();
 
+    PaintLayerScrollableAreaRareData* rareData()
+    {
+        return m_rareData.get();
+    }
+
+    PaintLayerScrollableAreaRareData& ensureRareData()
+    {
+        if (!m_rareData)
+            m_rareData = adoptPtr(new PaintLayerScrollableAreaRareData());
+        return *m_rareData.get();
+    }
+
     // PaintInvalidationCapableScrollableArea
     LayoutBox& boxForScrollControlPaintInvalidation() const { return box(); }
 
@@ -421,6 +448,8 @@
 
     ScrollAnchor m_scrollAnchor;
 
+    OwnPtr<PaintLayerScrollableAreaRareData> m_rareData;
+
 #if ENABLE(ASSERT)
     bool m_hasBeenDisposed;
 #endif
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.cpp b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
index 31ac24a..05085ff 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.cpp
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.cpp
@@ -844,59 +844,9 @@
         rareNonInheritedData.access()->m_callbackSelectors.append(selector);
 }
 
-void ComputedStyle::clearContent()
+void ComputedStyle::setContent(ContentData* contentData)
 {
-    if (rareNonInheritedData->m_content)
-        rareNonInheritedData.access()->m_content = nullptr;
-}
-
-void ComputedStyle::appendContent(ContentData* contentData)
-{
-    Persistent<ContentData>& content = rareNonInheritedData.access()->m_content;
-    if (!content) {
-        content = contentData;
-        return;
-    }
-    ContentData* lastContent = content.get();
-    while (lastContent->next())
-        lastContent = lastContent->next();
-    lastContent->setNext(contentData);
-}
-
-void ComputedStyle::setContent(StyleImage* image)
-{
-    appendContent(ContentData::create(image));
-}
-
-void ComputedStyle::setContent(const String& string)
-{
-    Persistent<ContentData>& content = rareNonInheritedData.access()->m_content;
-    if (!content) {
-        content = ContentData::create(string);
-        return;
-    }
-
-    ContentData* lastContent = content.get();
-    while (lastContent->next())
-        lastContent = lastContent->next();
-
-    // We attempt to merge with the last ContentData if possible.
-    if (lastContent->isText()) {
-        TextContentData* textContent = toTextContentData(lastContent);
-        textContent->setText(textContent->text() + string);
-    } else {
-        lastContent->setNext(ContentData::create(string));
-    }
-}
-
-void ComputedStyle::setContent(PassOwnPtr<CounterContent> counter)
-{
-    appendContent(ContentData::create(counter));
-}
-
-void ComputedStyle::setContent(QuoteType quote)
-{
-    appendContent(ContentData::create(quote));
+    SET_VAR(rareNonInheritedData, m_content, contentData);
 }
 
 bool ComputedStyle::hasWillChangeCompositingHint() const
diff --git a/third_party/WebKit/Source/core/style/ComputedStyle.h b/third_party/WebKit/Source/core/style/ComputedStyle.h
index e8cfa48..8c273afb 100644
--- a/third_party/WebKit/Source/core/style/ComputedStyle.h
+++ b/third_party/WebKit/Source/core/style/ComputedStyle.h
@@ -112,7 +112,6 @@
 class BorderData;
 struct BorderEdge;
 class CSSVariableData;
-class CounterContent;
 class Font;
 class FontMetrics;
 class RotateTransformOperation;
@@ -501,7 +500,7 @@
     EPosition position() const { return static_cast<EPosition>(noninherited_flags.position); }
     bool hasOutOfFlowPosition() const { return position() == AbsolutePosition || position() == FixedPosition; }
     bool hasInFlowPosition() const { return position() == RelativePosition || position() == StickyPosition; }
-    bool hasViewportConstrainedPosition() const { return position() == FixedPosition; }
+    bool hasViewportConstrainedPosition() const { return position() == FixedPosition || position() == StickyPosition; }
     EFloat floating() const { return static_cast<EFloat>(noninherited_flags.floating); }
 
     const Length& width() const { return m_box->width(); }
@@ -1589,11 +1588,7 @@
     bool hasContent() const { return contentData(); }
     ContentData* contentData() const { return rareNonInheritedData->m_content.get(); }
     bool contentDataEquivalent(const ComputedStyle* otherStyle) const { return const_cast<ComputedStyle*>(this)->rareNonInheritedData->contentDataEquivalent(*const_cast<ComputedStyle*>(otherStyle)->rareNonInheritedData); }
-    void clearContent();
-    void setContent(const String&);
-    void setContent(StyleImage*);
-    void setContent(PassOwnPtr<CounterContent>);
-    void setContent(QuoteType);
+    void setContent(ContentData*);
 
     const CounterDirectiveMap* counterDirectives() const;
     CounterDirectiveMap& accessCounterDirectives();
@@ -1926,7 +1921,6 @@
     Color floodColor() const { return svgStyle().floodColor(); }
     Color lightingColor() const { return svgStyle().lightingColor(); }
 
-    void appendContent(ContentData*);
     void addAppliedTextDecoration(const AppliedTextDecoration&);
     void applyMotionPathTransform(float originX, float originY, TransformationMatrix&) const;
 
diff --git a/third_party/WebKit/Source/core/svg/SVGElement.cpp b/third_party/WebKit/Source/core/svg/SVGElement.cpp
index 69e4735..2b6a5e0 100644
--- a/third_party/WebKit/Source/core/svg/SVGElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGElement.cpp
@@ -680,8 +680,7 @@
 
 void SVGElement::addToPropertyMap(SVGAnimatedPropertyBase* property)
 {
-    QualifiedName attributeName = property->attributeName();
-    m_attributeToPropertyMap.set(attributeName, property);
+    m_attributeToPropertyMap.set(property->attributeName(), property);
 }
 
 SVGAnimatedPropertyBase* SVGElement::propertyFromAttribute(const QualifiedName& attributeName) const
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaDevices.h b/third_party/WebKit/Source/modules/mediastream/MediaDevices.h
index b32a724..bed671c0 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaDevices.h
+++ b/third_party/WebKit/Source/modules/mediastream/MediaDevices.h
@@ -11,6 +11,7 @@
 namespace blink {
 
 class MediaStreamConstraints;
+class MediaTrackSupportedConstraints;
 class ScriptState;
 
 class MediaDevices final : public GarbageCollected<MediaDevices>, public ScriptWrappable {
@@ -22,6 +23,7 @@
     }
 
     ScriptPromise enumerateDevices(ScriptState*);
+    void getSupportedConstraints(MediaTrackSupportedConstraints& result) { }
     ScriptPromise getUserMedia(ScriptState*, const MediaStreamConstraints&, ExceptionState&);
     DEFINE_INLINE_TRACE() { }
 
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl b/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
index 78a00ad..2493bad 100644
--- a/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
+++ b/third_party/WebKit/Source/modules/mediastream/MediaDevices.idl
@@ -11,5 +11,6 @@
 ]
 interface MediaDevices {
     [CallWith=ScriptState, MeasureAs=MediaDevicesEnumerateDevices] Promise<sequence<MediaDeviceInfo>> enumerateDevices();
+    [RuntimeEnabled=MediaConstraints] MediaTrackSupportedConstraints getSupportedConstraints();
     [RuntimeEnabled=GetUserMedia, CallWith=ScriptState, RaisesException] Promise<MediaStream> getUserMedia(MediaStreamConstraints options);
 };
diff --git a/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl b/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl
new file mode 100644
index 0000000..ed3ae91
--- /dev/null
+++ b/third_party/WebKit/Source/modules/mediastream/MediaTrackSupportedConstraints.idl
@@ -0,0 +1,25 @@
+// 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.
+
+// https://w3c.github.io/mediacapture-main/getusermedia.html#idl-def-MediaTrackSupportedConstraints
+
+// NOTE: The names of this dictionary MUST be kept aligned with those in
+// MediaTrackConstraintSet.idl.
+
+[RuntimeEnabled=MediaConstraints] 
+dictionary MediaTrackSupportedConstraints {
+    boolean width = true;
+    boolean height = true;
+    boolean aspectRatio = true;
+    boolean frameRate = true;
+    boolean facingMode = true;
+    boolean volume = true;
+    boolean sampleRate = true;
+    boolean sampleSize = true;
+    boolean echoCancellation = true;
+    boolean latency = true;
+    boolean channelCount = true;
+    boolean deviceId = true;
+    boolean groupId = true;
+};
diff --git a/third_party/WebKit/Source/modules/modules.gypi b/third_party/WebKit/Source/modules/modules.gypi
index 4cfaa4b2..78cfea3 100644
--- a/third_party/WebKit/Source/modules/modules.gypi
+++ b/third_party/WebKit/Source/modules/modules.gypi
@@ -489,6 +489,7 @@
       'mediastream/MediaStreamConstraints.idl',
       'mediastream/MediaStreamEventInit.idl',
       'mediastream/MediaTrackConstraintSet.idl',
+      'mediastream/MediaTrackSupportedConstraints.idl',
       'mediastream/RTCAnswerOptions.idl',
       'mediastream/RTCDTMFToneChangeEventInit.idl',
       'mediastream/RTCIceCandidateInit.idl',
@@ -631,6 +632,8 @@
       '<(blink_modules_output_dir)/mediastream/MediaStreamEventInit.h',
       '<(blink_modules_output_dir)/mediastream/MediaTrackConstraintSet.cpp',
       '<(blink_modules_output_dir)/mediastream/MediaTrackConstraintSet.h',
+      '<(blink_modules_output_dir)/mediastream/MediaTrackSupportedConstraints.cpp',
+      '<(blink_modules_output_dir)/mediastream/MediaTrackSupportedConstraints.h',
       '<(blink_modules_output_dir)/mediastream/RTCAnswerOptions.cpp',
       '<(blink_modules_output_dir)/mediastream/RTCAnswerOptions.h',
       '<(blink_modules_output_dir)/mediastream/RTCDTMFToneChangeEventInit.cpp',
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
index d0a10078..d29e1d56 100644
--- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
+++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -54,7 +54,7 @@
 CSSPaintAPI status=test, depends_on=Worklet
 CSSPropertyD status=experimental
 CSSSnapSize status=experimental
-CSSStickyPosition
+CSSStickyPosition status=experimental
 CSSTouchActionPanDirections status=experimental
 CSSTypedOM status=experimental
 CSSVariables status=stable
diff --git a/third_party/WebKit/Source/platform/fonts/FontDescription.h b/third_party/WebKit/Source/platform/fonts/FontDescription.h
index a382603c..88faa3a 100644
--- a/third_party/WebKit/Source/platform/fonts/FontDescription.h
+++ b/third_party/WebKit/Source/platform/fonts/FontDescription.h
@@ -308,7 +308,7 @@
         && m_wordSpacing == other.m_wordSpacing
         && m_fieldsAsUnsigned[0] == other.m_fieldsAsUnsigned[0]
         && m_fieldsAsUnsigned[1] == other.m_fieldsAsUnsigned[1]
-        && m_featureSettings == other.m_featureSettings;
+        && (m_featureSettings == other.m_featureSettings || (m_featureSettings && other.m_featureSettings && *m_featureSettings == *other.m_featureSettings));
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.cpp b/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.cpp
index 78caa10..46bd936 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.cpp
@@ -33,7 +33,7 @@
 {
 }
 
-bool FontFeature::operator==(const FontFeature& other)
+bool FontFeature::operator==(const FontFeature& other) const
 {
     return m_tag == other.m_tag && m_value == other.m_value;
 }
@@ -42,4 +42,9 @@
 {
 }
 
+bool FontFeatureSettings::operator==(const FontFeatureSettings& other) const
+{
+    return m_list == other.m_list;
+}
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.h b/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.h
index 3e8c87a3..8d1c000 100644
--- a/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.h
+++ b/third_party/WebKit/Source/platform/fonts/FontFeatureSettings.h
@@ -40,7 +40,7 @@
     DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
 public:
     FontFeature(const AtomicString& tag, int value);
-    bool operator==(const FontFeature&);
+    bool operator==(const FontFeature&) const;
 
     const AtomicString& tag() const { return m_tag; }
     int value() const { return m_value; }
@@ -61,6 +61,7 @@
     size_t size() const { return m_list.size(); }
     const FontFeature& operator[](int index) const { return m_list[index]; }
     const FontFeature& at(size_t index) const { return m_list.at(index); }
+    bool operator==(const FontFeatureSettings&) const;
 
 private:
     FontFeatureSettings();
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
index 312dba24..437b453 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
@@ -374,7 +374,7 @@
     // the latter case.
     const bool isDecodeComplete = frame->getStatus() == ImageFrame::FrameComplete || allDataReceived;
 
-    SkBitmap fullSizeBitmap = frame->getSkBitmap();
+    SkBitmap fullSizeBitmap = frame->bitmap();
     if (!fullSizeBitmap.isNull()) {
         ASSERT(fullSizeBitmap.width() == m_fullSize.width() && fullSizeBitmap.height() == m_fullSize.height());
         setHasAlpha(index, !fullSizeBitmap.isOpaque());
diff --git a/third_party/WebKit/Source/platform/graphics/PictureSnapshot.cpp b/third_party/WebKit/Source/platform/graphics/PictureSnapshot.cpp
index e5ff225..2034450 100644
--- a/third_party/WebKit/Source/platform/graphics/PictureSnapshot.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PictureSnapshot.cpp
@@ -64,7 +64,7 @@
     ImageFrame* frame = imageDecoder->frameBufferAtIndex(0);
     if (!frame)
         return true;
-    *result = frame->getSkBitmap();
+    *result = frame->bitmap();
     return true;
 }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
index c6e3e435..3c51d4d 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoderTestHelpers.cpp
@@ -52,7 +52,7 @@
     size_t frameCount = decoder->frameCount();
     for (size_t i = 0; i < frameCount; ++i) {
         ImageFrame* frame = decoder->frameBufferAtIndex(i);
-        baselineHashes->append(hashBitmap(frame->getSkBitmap()));
+        baselineHashes->append(hashBitmap(frame->bitmap()));
     }
 }
 
@@ -99,7 +99,7 @@
     ASSERT_EQ(expectedFrameCount, baselineHashes.size());
     for (size_t i = 0; i < decoder->frameCount(); i++) {
         ImageFrame* frame = decoder->frameBufferAtIndex(i);
-        EXPECT_EQ(baselineHashes[i], hashBitmap(frame->getSkBitmap()));
+        EXPECT_EQ(baselineHashes[i], hashBitmap(frame->bitmap()));
     }
 }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
index a2a7f2a8..13904396 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.cpp
@@ -107,11 +107,6 @@
     return true;
 }
 
-const SkBitmap& ImageFrame::bitmap() const
-{
-    return m_bitmap;
-}
-
 bool ImageFrame::hasAlpha() const
 {
     return m_hasAlpha;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
index 80b8fa3..7a51c75 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageFrame.h
@@ -113,11 +113,6 @@
     // succeeded.
     bool setSize(int newWidth, int newHeight);
 
-    // Returns a caller-owned pointer to the underlying native image data.
-    // (Actual use: This pointer will be owned by BitmapImage and freed in
-    // FrameData::clear()).
-    const SkBitmap& bitmap() const;
-
     bool hasAlpha() const;
     const IntRect& originalFrameRect() const { return m_originalFrameRect; }
     Status getStatus() const { return m_status; }
@@ -126,7 +121,7 @@
     AlphaBlendSource getAlphaBlendSource() const { return m_alphaBlendSource; }
     bool premultiplyAlpha() const { return m_premultiplyAlpha; }
     SkBitmap::Allocator* allocator() const { return m_allocator; }
-    const SkBitmap& getSkBitmap() const { return m_bitmap; }
+    const SkBitmap& bitmap() const { return m_bitmap; }
     // Returns true if the pixels changed, but the bitmap has not yet been notified.
     bool pixelsChanged() const { return m_pixelsChanged; }
     size_t requiredPreviousFrameIndex() const { return m_requiredPreviousFrameIndex; }
diff --git a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoderTest.cpp
index 8b86f0e..1e2bc10 100644
--- a/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/bmp/BMPImageDecoderTest.cpp
@@ -44,8 +44,8 @@
     ImageFrame* frame = decoder->frameBufferAtIndex(0);
     ASSERT_TRUE(frame);
     EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-    EXPECT_EQ(256, frame->getSkBitmap().width());
-    EXPECT_EQ(256, frame->getSkBitmap().height());
+    EXPECT_EQ(256, frame->bitmap().width());
+    EXPECT_EQ(256, frame->bitmap().height());
     EXPECT_FALSE(decoder->failed());
 }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp
index 9a0d7dc5..756eb33 100644
--- a/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/gif/GIFImageDecoderTest.cpp
@@ -69,7 +69,7 @@
         for (size_t j = i; j < frameCount; j += skippingStep) {
             SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
             ImageFrame* frame = decoder->frameBufferAtIndex(j);
-            EXPECT_EQ(baselineHashes[j], hashBitmap(frame->getSkBitmap()));
+            EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
         }
     }
 
@@ -79,7 +79,7 @@
     for (size_t i = frameCount; i; --i) {
         SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
         ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
-        EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->getSkBitmap()));
+        EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->bitmap()));
     }
 }
 
@@ -102,7 +102,7 @@
             for (size_t j = 0; j < frameCount; j += skippingStep) {
                 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
                 ImageFrame* frame = decoder->frameBufferAtIndex(j);
-                EXPECT_EQ(baselineHashes[j], hashBitmap(frame->getSkBitmap()));
+                EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
             }
         }
     }
@@ -120,16 +120,16 @@
     EXPECT_EQ(cAnimationLoopOnce, decoder->repetitionCount());
 
     ImageFrame* frame = decoder->frameBufferAtIndex(0);
-    uint32_t generationID0 = frame->getSkBitmap().getGenerationID();
+    uint32_t generationID0 = frame->bitmap().getGenerationID();
     EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-    EXPECT_EQ(16, frame->getSkBitmap().width());
-    EXPECT_EQ(16, frame->getSkBitmap().height());
+    EXPECT_EQ(16, frame->bitmap().width());
+    EXPECT_EQ(16, frame->bitmap().height());
 
     frame = decoder->frameBufferAtIndex(1);
-    uint32_t generationID1 = frame->getSkBitmap().getGenerationID();
+    uint32_t generationID1 = frame->bitmap().getGenerationID();
     EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-    EXPECT_EQ(16, frame->getSkBitmap().width());
-    EXPECT_EQ(16, frame->getSkBitmap().height());
+    EXPECT_EQ(16, frame->bitmap().width());
+    EXPECT_EQ(16, frame->bitmap().height());
     EXPECT_TRUE(generationID0 != generationID1);
 
     EXPECT_EQ(2u, decoder->frameCount());
@@ -150,13 +150,13 @@
 
     ImageFrame* frame = decoder->frameBufferAtIndex(0);
     EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-    EXPECT_EQ(16, frame->getSkBitmap().width());
-    EXPECT_EQ(16, frame->getSkBitmap().height());
+    EXPECT_EQ(16, frame->bitmap().width());
+    EXPECT_EQ(16, frame->bitmap().height());
 
     frame = decoder->frameBufferAtIndex(1);
     EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-    EXPECT_EQ(16, frame->getSkBitmap().width());
-    EXPECT_EQ(16, frame->getSkBitmap().height());
+    EXPECT_EQ(16, frame->bitmap().width());
+    EXPECT_EQ(16, frame->bitmap().height());
     EXPECT_EQ(cAnimationLoopInfinite, decoder->repetitionCount());
 }
 
@@ -250,7 +250,7 @@
             truncatedHashes.append(0);
             continue;
         }
-        truncatedHashes.append(hashBitmap(frame->getSkBitmap()));
+        truncatedHashes.append(hashBitmap(frame->bitmap()));
     }
 
     // Compute hashes when the file is progressively decoded.
@@ -264,7 +264,7 @@
             progressiveHashes.append(0);
             continue;
         }
-        progressiveHashes.append(hashBitmap(frame->getSkBitmap()));
+        progressiveHashes.append(hashBitmap(frame->bitmap()));
     }
     EXPECT_EQ(cAnimationNone, decoder->repetitionCount());
 
@@ -354,7 +354,7 @@
     ImageFrame* testFrame = testDecoder->frameBufferAtIndex(0);
     ASSERT(testFrame);
 
-    EXPECT_EQ(hashBitmap(referenceFrame->getSkBitmap()), hashBitmap(testFrame->getSkBitmap()));
+    EXPECT_EQ(hashBitmap(referenceFrame->bitmap()), hashBitmap(testFrame->bitmap()));
 }
 
 TEST(GIFImageDecoderTest, updateRequiredPreviousFrameAfterFirstDecode)
@@ -423,13 +423,13 @@
     decoder->setData(fullData.get(), true);
     EXPECT_EQ(frameCount, decoder->frameCount());
     ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
-    EXPECT_EQ(baselineHashes[frameCount - 1], hashBitmap(lastFrame->getSkBitmap()));
+    EXPECT_EQ(baselineHashes[frameCount - 1], hashBitmap(lastFrame->bitmap()));
     decoder->clearCacheExceptFrame(kNotFound);
 
     // Resume decoding of the first frame.
     ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
     EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->getStatus());
-    EXPECT_EQ(baselineHashes[0], hashBitmap(firstFrame->getSkBitmap()));
+    EXPECT_EQ(baselineHashes[0], hashBitmap(firstFrame->bitmap()));
 }
 
 // The first LZW codes in the image are invalid values that try to create a loop
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
index e69d743..6386c22c 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
@@ -68,8 +68,8 @@
 
     ImageFrame* frame = decoder->frameBufferAtIndex(0);
     ASSERT_TRUE(frame);
-    *outputWidth = frame->getSkBitmap().width();
-    *outputHeight = frame->getSkBitmap().height();
+    *outputWidth = frame->bitmap().width();
+    *outputHeight = frame->bitmap().height();
     EXPECT_EQ(IntSize(*outputWidth, *outputHeight), decoder->decodedSize());
 }
 
diff --git a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoderTest.cpp
index b8c5cd7..b3474e3 100644
--- a/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/webp/WEBPImageDecoderTest.cpp
@@ -73,7 +73,7 @@
         for (size_t j = i; j < frameCount; j += skippingStep) {
             SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
             ImageFrame* frame = decoder->frameBufferAtIndex(j);
-            EXPECT_EQ(baselineHashes[j], hashBitmap(frame->getSkBitmap()));
+            EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
         }
     }
 
@@ -83,7 +83,7 @@
     for (size_t i = frameCount; i; --i) {
         SCOPED_TRACE(testing::Message() << "Reverse i:" << i);
         ImageFrame* frame = decoder->frameBufferAtIndex(i - 1);
-        EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->getSkBitmap()));
+        EXPECT_EQ(baselineHashes[i - 1], hashBitmap(frame->bitmap()));
     }
 }
 
@@ -106,7 +106,7 @@
             for (size_t j = 0; j < frameCount; j += skippingStep) {
                 SCOPED_TRACE(testing::Message() << "Random i:" << i << " j:" << j);
                 ImageFrame* frame = decoder->frameBufferAtIndex(j);
-                EXPECT_EQ(baselineHashes[j], hashBitmap(frame->getSkBitmap()));
+                EXPECT_EQ(baselineHashes[j], hashBitmap(frame->bitmap()));
             }
         }
     }
@@ -207,8 +207,8 @@
 
 void verifyFramesMatch(const char* webpFile, const ImageFrame* const a, ImageFrame* const b)
 {
-    const SkBitmap& bitmapA = a->getSkBitmap();
-    const SkBitmap& bitmapB = b->getSkBitmap();
+    const SkBitmap& bitmapA = a->bitmap();
+    const SkBitmap& bitmapB = b->bitmap();
     ASSERT_EQ(bitmapA.width(), bitmapB.width());
     ASSERT_EQ(bitmapA.height(), bitmapB.height());
 
@@ -266,9 +266,9 @@
     decoder->setData(data.get(), true);
 
     ImageFrame* frame = decoder->frameBufferAtIndex(0);
-    uint32_t generationID0 = frame->getSkBitmap().getGenerationID();
+    uint32_t generationID0 = frame->bitmap().getGenerationID();
     frame = decoder->frameBufferAtIndex(1);
-    uint32_t generationID1 = frame->getSkBitmap().getGenerationID();
+    uint32_t generationID1 = frame->bitmap().getGenerationID();
 
     EXPECT_TRUE(generationID0 != generationID1);
 }
@@ -299,8 +299,8 @@
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(frameParameters); ++i) {
         const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
         EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-        EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
-        EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
+        EXPECT_EQ(canvasWidth, frame->bitmap().width());
+        EXPECT_EQ(canvasHeight, frame->bitmap().height());
         EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
         EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
         EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
@@ -342,8 +342,8 @@
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(frameParameters); ++i) {
         const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
         EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-        EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
-        EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
+        EXPECT_EQ(canvasWidth, frame->bitmap().width());
+        EXPECT_EQ(canvasHeight, frame->bitmap().height());
         EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
         EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
         EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
@@ -385,8 +385,8 @@
     for (size_t i = 0; i < WTF_ARRAY_LENGTH(frameParameters); ++i) {
         const ImageFrame* const frame = decoder->frameBufferAtIndex(i);
         EXPECT_EQ(ImageFrame::FrameComplete, frame->getStatus());
-        EXPECT_EQ(canvasWidth, frame->getSkBitmap().width());
-        EXPECT_EQ(canvasHeight, frame->getSkBitmap().height());
+        EXPECT_EQ(canvasWidth, frame->bitmap().width());
+        EXPECT_EQ(canvasHeight, frame->bitmap().height());
         EXPECT_EQ(frameParameters[i].xOffset, frame->originalFrameRect().x());
         EXPECT_EQ(frameParameters[i].yOffset, frame->originalFrameRect().y());
         EXPECT_EQ(frameParameters[i].width, frame->originalFrameRect().width());
@@ -508,7 +508,7 @@
             truncatedHashes.append(0);
             continue;
         }
-        truncatedHashes.append(hashBitmap(frame->getSkBitmap()));
+        truncatedHashes.append(hashBitmap(frame->bitmap()));
     }
 
     // Compute hashes when the file is progressively decoded.
@@ -521,7 +521,7 @@
             progressiveHashes.append(0);
             continue;
         }
-        progressiveHashes.append(hashBitmap(frame->getSkBitmap()));
+        progressiveHashes.append(hashBitmap(frame->bitmap()));
     }
 
     bool match = true;
@@ -626,13 +626,13 @@
     decoder->setData(fullData.get(), true);
     EXPECT_EQ(frameCount, decoder->frameCount());
     ImageFrame* lastFrame = decoder->frameBufferAtIndex(frameCount - 1);
-    EXPECT_EQ(baselineHashes[frameCount - 1], hashBitmap(lastFrame->getSkBitmap()));
+    EXPECT_EQ(baselineHashes[frameCount - 1], hashBitmap(lastFrame->bitmap()));
     decoder->clearCacheExceptFrame(kNotFound);
 
     // Resume decoding of the first frame.
     ImageFrame* firstFrame = decoder->frameBufferAtIndex(0);
     EXPECT_EQ(ImageFrame::FrameComplete, firstFrame->getStatus());
-    EXPECT_EQ(baselineHashes[0], hashBitmap(firstFrame->getSkBitmap()));
+    EXPECT_EQ(baselineHashes[0], hashBitmap(firstFrame->bitmap()));
 }
 
 TEST(AnimatedWebPTests, decodeAfterReallocatingData)
diff --git a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
index f91cc686..0889a3f 100644
--- a/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
+++ b/third_party/WebKit/Source/web/WebRemoteFrameImpl.cpp
@@ -612,10 +612,7 @@
 {
     DCHECK(source);
     WebLocalFrameImpl* localFrameImpl = toWebLocalFrameImpl(source);
-
-    client()->initializeChildFrame(
-        localFrameImpl->frame()->view()->frameRect(),
-        localFrameImpl->frame()->page()->deviceScaleFactor());
+    client()->initializeChildFrame(localFrameImpl->frame()->page()->deviceScaleFactor());
 }
 
 void WebRemoteFrameImpl::setReplicatedOrigin(const WebSecurityOrigin& origin) const
diff --git a/third_party/WebKit/Source/wtf/ThreadingPthreads.cpp b/third_party/WebKit/Source/wtf/ThreadingPthreads.cpp
index cf2eed6..b270215 100644
--- a/third_party/WebKit/Source/wtf/ThreadingPthreads.cpp
+++ b/third_party/WebKit/Source/wtf/ThreadingPthreads.cpp
@@ -41,8 +41,7 @@
 #include "wtf/ThreadSpecific.h"
 #include "wtf/ThreadingPrimitives.h"
 #include "wtf/WTFThreadData.h"
-#include "wtf/dtoa.h"
-#include "wtf/dtoa/cached-powers.h"
+#include "wtf/dtoa/double-conversion.h"
 #include <errno.h>
 #include <limits.h>
 #include <sched.h>
@@ -75,7 +74,6 @@
     StringImpl::empty16Bit();
     atomicallyInitializedStaticMutex = new Mutex;
     wtfThreadData();
-    s_dtoaP5Mutex = new Mutex;
     initializeDates();
     // Force initialization of static DoubleToStringConverter converter variable
     // inside EcmaScriptConverter function while we are in single thread mode.
diff --git a/third_party/WebKit/Source/wtf/ThreadingWin.cpp b/third_party/WebKit/Source/wtf/ThreadingWin.cpp
index d4c26d7e..c7eeef15 100644
--- a/third_party/WebKit/Source/wtf/ThreadingWin.cpp
+++ b/third_party/WebKit/Source/wtf/ThreadingWin.cpp
@@ -96,8 +96,7 @@
 #include "wtf/ThreadSpecific.h"
 #include "wtf/ThreadingPrimitives.h"
 #include "wtf/WTFThreadData.h"
-#include "wtf/dtoa.h"
-#include "wtf/dtoa/cached-powers.h"
+#include "wtf/dtoa/double-conversion.h"
 #include <errno.h>
 #include <process.h>
 #include <windows.h>
@@ -138,7 +137,6 @@
     StringImpl::empty16Bit();
     atomicallyInitializedStaticMutex = new Mutex;
     wtfThreadData();
-    s_dtoaP5Mutex = new Mutex;
     initializeDates();
     // Force initialization of static DoubleToStringConverter converter variable
     // inside EcmaScriptConverter function while we are in single thread mode.
diff --git a/third_party/WebKit/Source/wtf/dtoa.cpp b/third_party/WebKit/Source/wtf/dtoa.cpp
index 508cb98..db2826b7 100644
--- a/third_party/WebKit/Source/wtf/dtoa.cpp
+++ b/third_party/WebKit/Source/wtf/dtoa.cpp
@@ -34,1194 +34,11 @@
 
 #include "wtf/dtoa.h"
 
-#include "wtf/CPU.h"
-#include "wtf/MathExtras.h"
-#include "wtf/ThreadingPrimitives.h"
 #include "wtf/Vector.h"
 #include <string.h>
 
-#if COMPILER(MSVC)
-#pragma warning(disable: 4244)
-#pragma warning(disable: 4245)
-#pragma warning(disable: 4554)
-#endif
-
 namespace WTF {
 
-Mutex* s_dtoaP5Mutex;
-
-typedef union {
-    double d;
-    uint32_t L[2];
-} U;
-
-#if CPU(BIG_ENDIAN) || CPU(MIDDLE_ENDIAN)
-#define word0(x) (x)->L[0]
-#define word1(x) (x)->L[1]
-#else
-#define word0(x) (x)->L[1]
-#define word1(x) (x)->L[0]
-#endif
-#define dval(x) (x)->d
-
-#define Exp_shift  20
-#define Exp_shift1 20
-#define Exp_msk1    0x100000
-#define Exp_msk11   0x100000
-#define Exp_mask  0x7ff00000
-#define P 53
-#define Bias 1023
-#define Emin (-1022)
-#define Exp_1  0x3ff00000
-#define Exp_11 0x3ff00000
-#define Ebits 11
-#define Frac_mask  0xfffff
-#define Frac_mask1 0xfffff
-#define Ten_pmax 22
-#define Bletch 0x10
-#define Bndry_mask  0xfffff
-#define Bndry_mask1 0xfffff
-#define LSB 1
-#define Sign_bit 0x80000000
-#define Log2P 1
-#define Tiny0 0
-#define Tiny1 1
-#define Quick_max 14
-#define Int_max 14
-
-#define rounded_product(a, b) a *= b
-#define rounded_quotient(a, b) a /= b
-
-#define Big0 (Frac_mask1 | Exp_msk1 * (DBL_MAX_EXP + Bias - 1))
-#define Big1 0xffffffff
-
-#if CPU(X86_64)
-// FIXME: should we enable this on all 64-bit CPUs?
-// 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware.
-#define USE_LONG_LONG
-#endif
-
-#ifndef USE_LONG_LONG
-/* The following definition of Storeinc is appropriate for MIPS processors.
- * An alternative that might be better on some machines is
- *  *p++ = high << 16 | low & 0xffff;
- */
-static ALWAYS_INLINE uint32_t* storeInc(uint32_t* p, uint16_t high, uint16_t low)
-{
-    uint16_t* p16 = reinterpret_cast<uint16_t*>(p);
-#if CPU(BIG_ENDIAN)
-    p16[0] = high;
-    p16[1] = low;
-#else
-    p16[1] = high;
-    p16[0] = low;
-#endif
-    return p + 1;
-}
-#endif
-
-struct BigInt {
-    BigInt() : sign(0) { }
-    int sign;
-
-    void clear()
-    {
-        sign = 0;
-        m_words.clear();
-    }
-
-    size_t size() const
-    {
-        return m_words.size();
-    }
-
-    void resize(size_t s)
-    {
-        m_words.resize(s);
-    }
-
-    uint32_t* words()
-    {
-        return m_words.data();
-    }
-
-    const uint32_t* words() const
-    {
-        return m_words.data();
-    }
-
-    void append(uint32_t w)
-    {
-        m_words.append(w);
-    }
-
-    Vector<uint32_t, 16> m_words;
-};
-
-static void multadd(BigInt& b, int m, int a)    /* multiply by m and add a */
-{
-#ifdef USE_LONG_LONG
-    unsigned long long carry;
-#else
-    uint32_t carry;
-#endif
-
-    int wds = b.size();
-    uint32_t* x = b.words();
-    int i = 0;
-    carry = a;
-    do {
-#ifdef USE_LONG_LONG
-        unsigned long long y = *x * (unsigned long long)m + carry;
-        carry = y >> 32;
-        *x++ = (uint32_t)y & 0xffffffffUL;
-#else
-        uint32_t xi = *x;
-        uint32_t y = (xi & 0xffff) * m + carry;
-        uint32_t z = (xi >> 16) * m + (y >> 16);
-        carry = z >> 16;
-        *x++ = (z << 16) + (y & 0xffff);
-#endif
-    } while (++i < wds);
-
-    if (carry)
-        b.append((uint32_t)carry);
-}
-
-static int hi0bits(uint32_t x)
-{
-    int k = 0;
-
-    if (!(x & 0xffff0000)) {
-        k = 16;
-        x <<= 16;
-    }
-    if (!(x & 0xff000000)) {
-        k += 8;
-        x <<= 8;
-    }
-    if (!(x & 0xf0000000)) {
-        k += 4;
-        x <<= 4;
-    }
-    if (!(x & 0xc0000000)) {
-        k += 2;
-        x <<= 2;
-    }
-    if (!(x & 0x80000000)) {
-        k++;
-        if (!(x & 0x40000000))
-            return 32;
-    }
-    return k;
-}
-
-static int lo0bits(uint32_t* y)
-{
-    int k;
-    uint32_t x = *y;
-
-    if (x & 7) {
-        if (x & 1)
-            return 0;
-        if (x & 2) {
-            *y = x >> 1;
-            return 1;
-        }
-        *y = x >> 2;
-        return 2;
-    }
-    k = 0;
-    if (!(x & 0xffff)) {
-        k = 16;
-        x >>= 16;
-    }
-    if (!(x & 0xff)) {
-        k += 8;
-        x >>= 8;
-    }
-    if (!(x & 0xf)) {
-        k += 4;
-        x >>= 4;
-    }
-    if (!(x & 0x3)) {
-        k += 2;
-        x >>= 2;
-    }
-    if (!(x & 1)) {
-        k++;
-        x >>= 1;
-        if (!x)
-            return 32;
-    }
-    *y = x;
-    return k;
-}
-
-static void i2b(BigInt& b, int i)
-{
-    b.sign = 0;
-    b.resize(1);
-    b.words()[0] = i;
-}
-
-static void mult(BigInt& aRef, const BigInt& bRef)
-{
-    const BigInt* a = &aRef;
-    const BigInt* b = &bRef;
-    BigInt c;
-    int wa, wb, wc;
-    const uint32_t* x = 0;
-    const uint32_t* xa;
-    const uint32_t* xb;
-    const uint32_t* xae;
-    const uint32_t* xbe;
-    uint32_t* xc;
-    uint32_t* xc0;
-    uint32_t y;
-#ifdef USE_LONG_LONG
-    unsigned long long carry, z;
-#else
-    uint32_t carry, z;
-#endif
-
-    if (a->size() < b->size()) {
-        const BigInt* tmp = a;
-        a = b;
-        b = tmp;
-    }
-
-    wa = a->size();
-    wb = b->size();
-    wc = wa + wb;
-    c.resize(wc);
-
-    for (xc = c.words(), xa = xc + wc; xc < xa; xc++)
-        *xc = 0;
-    xa = a->words();
-    xae = xa + wa;
-    xb = b->words();
-    xbe = xb + wb;
-    xc0 = c.words();
-#ifdef USE_LONG_LONG
-    for (; xb < xbe; xc0++) {
-        if ((y = *xb++)) {
-            x = xa;
-            xc = xc0;
-            carry = 0;
-            do {
-                z = *x++ * (unsigned long long)y + *xc + carry;
-                carry = z >> 32;
-                *xc++ = (uint32_t)z & 0xffffffffUL;
-            } while (x < xae);
-            *xc = (uint32_t)carry;
-        }
-    }
-#else
-    for (; xb < xbe; xb++, xc0++) {
-        if ((y = *xb & 0xffff)) {
-            x = xa;
-            xc = xc0;
-            carry = 0;
-            do {
-                z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
-                carry = z >> 16;
-                uint32_t z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
-                carry = z2 >> 16;
-                xc = storeInc(xc, z2, z);
-            } while (x < xae);
-            *xc = carry;
-        }
-        if ((y = *xb >> 16)) {
-            x = xa;
-            xc = xc0;
-            carry = 0;
-            uint32_t z2 = *xc;
-            do {
-                z = (*x & 0xffff) * y + (*xc >> 16) + carry;
-                carry = z >> 16;
-                xc = storeInc(xc, z, z2);
-                z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
-                carry = z2 >> 16;
-            } while (x < xae);
-            *xc = z2;
-        }
-    }
-#endif
-    for (xc0 = c.words(), xc = xc0 + wc; wc > 0 && !*--xc; --wc) { }
-    c.resize(wc);
-    aRef = c;
-}
-
-struct P5Node {
-    WTF_MAKE_NONCOPYABLE(P5Node); USING_FAST_MALLOC(P5Node);
-public:
-    P5Node() { }
-    BigInt val;
-    P5Node* next;
-};
-
-static P5Node* p5s;
-static int p5sCount;
-
-static ALWAYS_INLINE void pow5mult(BigInt& b, int k)
-{
-    static int p05[3] = { 5, 25, 125 };
-
-    if (int i = k & 3)
-        multadd(b, p05[i - 1], 0);
-
-    if (!(k >>= 2))
-        return;
-
-    s_dtoaP5Mutex->lock();
-    P5Node* p5 = p5s;
-
-    if (!p5) {
-        /* first time */
-        p5 = new P5Node;
-        i2b(p5->val, 625);
-        p5->next = 0;
-        p5s = p5;
-        p5sCount = 1;
-    }
-
-    int p5sCountLocal = p5sCount;
-    s_dtoaP5Mutex->unlock();
-    int p5sUsed = 0;
-
-    for (;;) {
-        if (k & 1)
-            mult(b, p5->val);
-
-        if (!(k >>= 1))
-            break;
-
-        if (++p5sUsed == p5sCountLocal) {
-            s_dtoaP5Mutex->lock();
-            if (p5sUsed == p5sCount) {
-                ASSERT(!p5->next);
-                p5->next = new P5Node;
-                p5->next->next = 0;
-                p5->next->val = p5->val;
-                mult(p5->next->val, p5->next->val);
-                ++p5sCount;
-            }
-
-            p5sCountLocal = p5sCount;
-            s_dtoaP5Mutex->unlock();
-        }
-        p5 = p5->next;
-    }
-}
-
-static ALWAYS_INLINE void lshift(BigInt& b, int k)
-{
-    int n = k >> 5;
-
-    int origSize = b.size();
-    int n1 = n + origSize + 1;
-
-    if (k &= 0x1f)
-        b.resize(b.size() + n + 1);
-    else
-        b.resize(b.size() + n);
-
-    const uint32_t* srcStart = b.words();
-    uint32_t* dstStart = b.words();
-    const uint32_t* src = srcStart + origSize - 1;
-    uint32_t* dst = dstStart + n1 - 1;
-    if (k) {
-        uint32_t hiSubword = 0;
-        int s = 32 - k;
-        for (; src >= srcStart; --src) {
-            *dst-- = hiSubword | *src >> s;
-            hiSubword = *src << k;
-        }
-        *dst = hiSubword;
-        ASSERT(dst == dstStart + n);
-
-        b.resize(origSize + n + !!b.words()[n1 - 1]);
-    }
-    else {
-        do {
-            *--dst = *src--;
-        } while (src >= srcStart);
-    }
-    for (dst = dstStart + n; dst != dstStart; )
-        *--dst = 0;
-
-    ASSERT(b.size() <= 1 || b.words()[b.size() - 1]);
-}
-
-static int cmp(const BigInt& a, const BigInt& b)
-{
-    const uint32_t *xa, *xa0, *xb, *xb0;
-    int i, j;
-
-    i = a.size();
-    j = b.size();
-    ASSERT(i <= 1 || a.words()[i - 1]);
-    ASSERT(j <= 1 || b.words()[j - 1]);
-    if (i -= j)
-        return i;
-    xa0 = a.words();
-    xa = xa0 + j;
-    xb0 = b.words();
-    xb = xb0 + j;
-    for (;;) {
-        if (*--xa != *--xb)
-            return *xa < *xb ? -1 : 1;
-        if (xa <= xa0)
-            break;
-    }
-    return 0;
-}
-
-static ALWAYS_INLINE void diff(BigInt& c, const BigInt& aRef, const BigInt& bRef)
-{
-    const BigInt* a = &aRef;
-    const BigInt* b = &bRef;
-    int i, wa, wb;
-    uint32_t* xc;
-
-    i = cmp(*a, *b);
-    if (!i) {
-        c.sign = 0;
-        c.resize(1);
-        c.words()[0] = 0;
-        return;
-    }
-    if (i < 0) {
-        const BigInt* tmp = a;
-        a = b;
-        b = tmp;
-        i = 1;
-    } else
-        i = 0;
-
-    wa = a->size();
-    const uint32_t* xa = a->words();
-    const uint32_t* xae = xa + wa;
-    wb = b->size();
-    const uint32_t* xb = b->words();
-    const uint32_t* xbe = xb + wb;
-
-    c.resize(wa);
-    c.sign = i;
-    xc = c.words();
-#ifdef USE_LONG_LONG
-    unsigned long long borrow = 0;
-    do {
-        unsigned long long y = (unsigned long long)*xa++ - *xb++ - borrow;
-        borrow = y >> 32 & (uint32_t)1;
-        *xc++ = (uint32_t)y & 0xffffffffUL;
-    } while (xb < xbe);
-    while (xa < xae) {
-        unsigned long long y = *xa++ - borrow;
-        borrow = y >> 32 & (uint32_t)1;
-        *xc++ = (uint32_t)y & 0xffffffffUL;
-    }
-#else
-    uint32_t borrow = 0;
-    do {
-        uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
-        borrow = (y & 0x10000) >> 16;
-        uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
-        borrow = (z & 0x10000) >> 16;
-        xc = storeInc(xc, z, y);
-    } while (xb < xbe);
-    while (xa < xae) {
-        uint32_t y = (*xa & 0xffff) - borrow;
-        borrow = (y & 0x10000) >> 16;
-        uint32_t z = (*xa++ >> 16) - borrow;
-        borrow = (z & 0x10000) >> 16;
-        xc = storeInc(xc, z, y);
-    }
-#endif
-    while (!*--xc)
-        wa--;
-    c.resize(wa);
-}
-
-static ALWAYS_INLINE void d2b(BigInt& b, U* d, int* e, int* bits)
-{
-    int de, k;
-    uint32_t* x;
-    uint32_t y, z;
-    int i;
-#define d0 word0(d)
-#define d1 word1(d)
-
-    b.sign = 0;
-    b.resize(1);
-    x = b.words();
-
-    z = d0 & Frac_mask;
-    d0 &= 0x7fffffff;    /* clear sign bit, which we ignore */
-    if ((de = (int)(d0 >> Exp_shift)))
-        z |= Exp_msk1;
-    if ((y = d1)) {
-        if ((k = lo0bits(&y))) {
-            x[0] = y | (z << (32 - k));
-            z >>= k;
-        } else
-            x[0] = y;
-        if (z) {
-            b.resize(2);
-            x[1] = z;
-        }
-
-        i = b.size();
-    } else {
-        k = lo0bits(&z);
-        x[0] = z;
-        i = 1;
-        b.resize(1);
-        k += 32;
-    }
-    if (de) {
-        *e = de - Bias - (P - 1) + k;
-        *bits = P - k;
-    } else {
-        *e = 0 - Bias - (P - 1) + 1 + k;
-        *bits = (32 * i) - hi0bits(x[i - 1]);
-    }
-}
-#undef d0
-#undef d1
-
-static const double tens[] = {
-    1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
-    1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
-    1e20, 1e21, 1e22
-};
-
-static const double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
-
-#define Scale_Bit 0x10
-#define n_bigtens 5
-
-static ALWAYS_INLINE int quorem(BigInt& b, BigInt& s)
-{
-    size_t n;
-    uint32_t* bx;
-    uint32_t* bxe;
-    uint32_t q;
-    uint32_t* sx;
-    uint32_t* sxe;
-#ifdef USE_LONG_LONG
-    unsigned long long borrow, carry, y, ys;
-#else
-    uint32_t borrow, carry, y, ys;
-    uint32_t si, z, zs;
-#endif
-    ASSERT(b.size() <= 1 || b.words()[b.size() - 1]);
-    ASSERT(s.size() <= 1 || s.words()[s.size() - 1]);
-
-    n = s.size();
-    DCHECK_LE(b.size(), n) << "oversize b in quorem";
-    if (b.size() < n)
-        return 0;
-    sx = s.words();
-    sxe = sx + --n;
-    bx = b.words();
-    bxe = bx + n;
-    q = *bxe / (*sxe + 1);    /* ensure q <= true quotient */
-    DCHECK_LE(q, 9u) << "oversized quotient in quorem";
-    if (q) {
-        borrow = 0;
-        carry = 0;
-        do {
-#ifdef USE_LONG_LONG
-            ys = *sx++ * (unsigned long long)q + carry;
-            carry = ys >> 32;
-            y = *bx - (ys & 0xffffffffUL) - borrow;
-            borrow = y >> 32 & (uint32_t)1;
-            *bx++ = (uint32_t)y & 0xffffffffUL;
-#else
-            si = *sx++;
-            ys = (si & 0xffff) * q + carry;
-            zs = (si >> 16) * q + (ys >> 16);
-            carry = zs >> 16;
-            y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
-            borrow = (y & 0x10000) >> 16;
-            z = (*bx >> 16) - (zs & 0xffff) - borrow;
-            borrow = (z & 0x10000) >> 16;
-            bx = storeInc(bx, z, y);
-#endif
-        } while (sx <= sxe);
-        if (!*bxe) {
-            bx = b.words();
-            while (--bxe > bx && !*bxe)
-                --n;
-            b.resize(n);
-        }
-    }
-    if (cmp(b, s) >= 0) {
-        q++;
-        borrow = 0;
-        carry = 0;
-        bx = b.words();
-        sx = s.words();
-        do {
-#ifdef USE_LONG_LONG
-            ys = *sx++ + carry;
-            carry = ys >> 32;
-            y = *bx - (ys & 0xffffffffUL) - borrow;
-            borrow = y >> 32 & (uint32_t)1;
-            *bx++ = (uint32_t)y & 0xffffffffUL;
-#else
-            si = *sx++;
-            ys = (si & 0xffff) + carry;
-            zs = (si >> 16) + (ys >> 16);
-            carry = zs >> 16;
-            y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
-            borrow = (y & 0x10000) >> 16;
-            z = (*bx >> 16) - (zs & 0xffff) - borrow;
-            borrow = (z & 0x10000) >> 16;
-            bx = storeInc(bx, z, y);
-#endif
-        } while (sx <= sxe);
-        bx = b.words();
-        bxe = bx + n;
-        if (!*bxe) {
-            while (--bxe > bx && !*bxe)
-                --n;
-            b.resize(n);
-        }
-    }
-    return q;
-}
-
-/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
- *
- * Inspired by "How to Print Floating-Point Numbers Accurately" by
- * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
- *
- * Modifications:
- *    1. Rather than iterating, we use a simple numeric overestimate
- *       to determine k = floor(log10(d)).  We scale relevant
- *       quantities using O(log2(k)) rather than O(k) multiplications.
- *    2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
- *       try to generate digits strictly left to right.  Instead, we
- *       compute with fewer bits and propagate the carry if necessary
- *       when rounding the final digit up.  This is often faster.
- *    3. Under the assumption that input will be rounded nearest,
- *       mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
- *       That is, we allow equality in stopping tests when the
- *       round-nearest rule will give the same floating-point value
- *       as would satisfaction of the stopping test with strict
- *       inequality.
- *    4. We remove common factors of powers of 2 from relevant
- *       quantities.
- *    5. When converting floating-point integers less than 1e16,
- *       we use floating-point arithmetic rather than resorting
- *       to multiple-precision integers.
- *    6. When asked to produce fewer than 15 digits, we first try
- *       to get by with floating-point arithmetic; we resort to
- *       multiple-precision integer arithmetic only if we cannot
- *       guarantee that the floating-point calculation has given
- *       the correctly rounded result.  For k requested digits and
- *       "uniformly" distributed input, the probability is
- *       something like 10^(k-15) that we must resort to the int32_t
- *       calculation.
- *
- * Note: 'leftright' translates to 'generate shortest possible string'.
- */
-template<bool roundingNone, bool roundingSignificantFigures, bool roundingDecimalPlaces, bool leftright>
-void dtoa(DtoaBuffer result, double dd, int ndigits, bool& signOut, int& exponentOut, unsigned& precisionOut)
-{
-    // Exactly one rounding mode must be specified.
-    ASSERT(roundingNone + roundingSignificantFigures + roundingDecimalPlaces == 1);
-    // roundingNone only allowed (only sensible?) with leftright set.
-    ASSERT(!roundingNone || leftright);
-
-    ASSERT(std::isfinite(dd));
-
-    int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0,
-        j, j1, k, k0, k_check, m2, m5, s2, s5,
-        spec_case;
-    int32_t L;
-    int denorm;
-    uint32_t x;
-    BigInt b, delta, mlo, mhi, s;
-    U d2, eps, u;
-    double ds;
-    char* str;
-    char* str0;
-
-    u.d = dd;
-
-    /* Infinity or NaN */
-    ASSERT((word0(&u) & Exp_mask) != Exp_mask);
-
-    // JavaScript toString conversion treats -0 as 0.
-    if (!dval(&u)) {
-        signOut = false;
-        exponentOut = 0;
-        precisionOut = 1;
-        result[0] = '0';
-        result[1] = '\0';
-        return;
-    }
-
-    if (word0(&u) & Sign_bit) {
-        signOut = true;
-        word0(&u) &= ~Sign_bit; // clear sign bit
-    } else
-        signOut = false;
-
-    d2b(b, &u, &be, &bbits);
-    if ((i = (int)(word0(&u) >> Exp_shift1 & (Exp_mask >> Exp_shift1)))) {
-        dval(&d2) = dval(&u);
-        word0(&d2) &= Frac_mask1;
-        word0(&d2) |= Exp_11;
-
-        /* log(x)    ~=~ log(1.5) + (x-1.5)/1.5
-         * log10(x)     =  log(x) / log(10)
-         *        ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
-         * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
-         *
-         * This suggests computing an approximation k to log10(d) by
-         *
-         * k = (i - Bias)*0.301029995663981
-         *    + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
-         *
-         * We want k to be too large rather than too small.
-         * The error in the first-order Taylor series approximation
-         * is in our favor, so we just round up the constant enough
-         * to compensate for any error in the multiplication of
-         * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
-         * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
-         * adding 1e-13 to the constant term more than suffices.
-         * Hence we adjust the constant term to 0.1760912590558.
-         * (We could get a more accurate k by invoking log10,
-         *  but this is probably not worthwhile.)
-         */
-
-        i -= Bias;
-        denorm = 0;
-    } else {
-        /* d is denormalized */
-
-        i = bbits + be + (Bias + (P - 1) - 1);
-        x = (i > 32) ? (word0(&u) << (64 - i)) | (word1(&u) >> (i - 32))
-                : word1(&u) << (32 - i);
-        dval(&d2) = x;
-        word0(&d2) -= 31 * Exp_msk1; /* adjust exponent */
-        i -= (Bias + (P - 1) - 1) + 1;
-        denorm = 1;
-    }
-    ds = (dval(&d2) - 1.5) * 0.289529654602168 + 0.1760912590558 + (i * 0.301029995663981);
-    k = (int)ds;
-    if (ds < 0. && ds != k)
-        k--;    /* want k = floor(ds) */
-    k_check = 1;
-    if (k >= 0 && k <= Ten_pmax) {
-        if (dval(&u) < tens[k])
-            k--;
-        k_check = 0;
-    }
-    j = bbits - i - 1;
-    if (j >= 0) {
-        b2 = 0;
-        s2 = j;
-    } else {
-        b2 = -j;
-        s2 = 0;
-    }
-    if (k >= 0) {
-        b5 = 0;
-        s5 = k;
-        s2 += k;
-    } else {
-        b2 -= k;
-        b5 = -k;
-        s5 = 0;
-    }
-
-    if (roundingNone) {
-        ilim = ilim1 = -1;
-        i = 18;
-        ndigits = 0;
-    }
-    if (roundingSignificantFigures) {
-        if (ndigits <= 0)
-            ndigits = 1;
-        ilim = ilim1 = i = ndigits;
-    }
-    if (roundingDecimalPlaces) {
-        i = ndigits + k + 1;
-        ilim = i;
-        ilim1 = i - 1;
-        if (i <= 0)
-            i = 1;
-    }
-
-    str = str0 = result;
-
-    if (ilim >= 0 && ilim <= Quick_max) {
-        /* Try to get by with floating-point arithmetic. */
-
-        i = 0;
-        dval(&d2) = dval(&u);
-        k0 = k;
-        ilim0 = ilim;
-        ieps = 2; /* conservative */
-        if (k > 0) {
-            ds = tens[k & 0xf];
-            j = k >> 4;
-            if (j & Bletch) {
-                /* prevent overflows */
-                j &= Bletch - 1;
-                dval(&u) /= bigtens[n_bigtens - 1];
-                ieps++;
-            }
-            for (; j; j >>= 1, i++) {
-                if (j & 1) {
-                    ieps++;
-                    ds *= bigtens[i];
-                }
-            }
-            dval(&u) /= ds;
-        } else if ((j1 = -k)) {
-            dval(&u) *= tens[j1 & 0xf];
-            for (j = j1 >> 4; j; j >>= 1, i++) {
-                if (j & 1) {
-                    ieps++;
-                    dval(&u) *= bigtens[i];
-                }
-            }
-        }
-        if (k_check && dval(&u) < 1. && ilim > 0) {
-            if (ilim1 <= 0)
-                goto fastFailed;
-            ilim = ilim1;
-            k--;
-            dval(&u) *= 10.;
-            ieps++;
-        }
-        dval(&eps) = (ieps * dval(&u)) + 7.;
-        word0(&eps) -= (P - 1) * Exp_msk1;
-        if (!ilim) {
-            s.clear();
-            mhi.clear();
-            dval(&u) -= 5.;
-            if (dval(&u) > dval(&eps))
-                goto oneDigit;
-            if (dval(&u) < -dval(&eps))
-                goto noDigits;
-            goto fastFailed;
-        }
-        if (leftright) {
-            /* Use Steele & White method of only
-             * generating digits needed.
-             */
-            dval(&eps) = (0.5 / tens[ilim - 1]) - dval(&eps);
-            for (i = 0;;) {
-                L = (long int)dval(&u);
-                dval(&u) -= L;
-                *str++ = '0' + (int)L;
-                if (dval(&u) < dval(&eps))
-                    goto ret;
-                if (1. - dval(&u) < dval(&eps))
-                    goto bumpUp;
-                if (++i >= ilim)
-                    break;
-                dval(&eps) *= 10.;
-                dval(&u) *= 10.;
-            }
-        } else {
-            /* Generate ilim digits, then fix them up. */
-            dval(&eps) *= tens[ilim - 1];
-            for (i = 1;; i++, dval(&u) *= 10.) {
-                L = (int32_t)(dval(&u));
-                if (!(dval(&u) -= L))
-                    ilim = i;
-                *str++ = '0' + (int)L;
-                if (i == ilim) {
-                    if (dval(&u) > 0.5 + dval(&eps))
-                        goto bumpUp;
-                    if (dval(&u) < 0.5 - dval(&eps)) {
-                        while (*--str == '0') { }
-                        str++;
-                        goto ret;
-                    }
-                    break;
-                }
-            }
-        }
-fastFailed:
-        str = str0;
-        dval(&u) = dval(&d2);
-        k = k0;
-        ilim = ilim0;
-    }
-
-    /* Do we have a "small" integer? */
-
-    if (be >= 0 && k <= Int_max) {
-        /* Yes. */
-        ds = tens[k];
-        if (ndigits < 0 && ilim <= 0) {
-            s.clear();
-            mhi.clear();
-            if (ilim < 0 || dval(&u) <= 5 * ds)
-                goto noDigits;
-            goto oneDigit;
-        }
-        for (i = 1;; i++, dval(&u) *= 10.) {
-            L = (int32_t)(dval(&u) / ds);
-            dval(&u) -= L * ds;
-            *str++ = '0' + (int)L;
-            if (!dval(&u)) {
-                break;
-            }
-            if (i == ilim) {
-                dval(&u) += dval(&u);
-                if (dval(&u) > ds || (dval(&u) == ds && (L & 1))) {
-bumpUp:
-                    while (*--str == '9')
-                        if (str == str0) {
-                            k++;
-                            *str = '0';
-                            break;
-                        }
-                    ++*str++;
-                }
-                break;
-            }
-        }
-        goto ret;
-    }
-
-    m2 = b2;
-    m5 = b5;
-    mhi.clear();
-    mlo.clear();
-    if (leftright) {
-        i = denorm ? be + (Bias + (P - 1) - 1 + 1) : 1 + P - bbits;
-        b2 += i;
-        s2 += i;
-        i2b(mhi, 1);
-    }
-    if (m2 > 0 && s2 > 0) {
-        i = m2 < s2 ? m2 : s2;
-        b2 -= i;
-        m2 -= i;
-        s2 -= i;
-    }
-    if (b5 > 0) {
-        if (leftright) {
-            if (m5 > 0) {
-                pow5mult(mhi, m5);
-                mult(b, mhi);
-            }
-            if ((j = b5 - m5))
-                pow5mult(b, j);
-        } else
-            pow5mult(b, b5);
-    }
-    i2b(s, 1);
-    if (s5 > 0)
-        pow5mult(s, s5);
-
-    /* Check for special case that d is a normalized power of 2. */
-
-    spec_case = 0;
-    if ((roundingNone || leftright) && (!word1(&u) && !(word0(&u) & Bndry_mask) && word0(&u) & (Exp_mask & ~Exp_msk1))) {
-        /* The special case */
-        b2 += Log2P;
-        s2 += Log2P;
-        spec_case = 1;
-    }
-
-    /* Arrange for convenient computation of quotients:
-     * shift left if necessary so divisor has 4 leading 0 bits.
-     *
-     * Perhaps we should just compute leading 28 bits of s once
-     * and for all and pass them and a shift to quorem, so it
-     * can do shifts and ors to compute the numerator for q.
-     */
-    if ((i = ((s5 ? 32 - hi0bits(s.words()[s.size() - 1]) : 1) + s2) & 0x1f))
-        i = 32 - i;
-    if (i > 4) {
-        i -= 4;
-        b2 += i;
-        m2 += i;
-        s2 += i;
-    } else if (i < 4) {
-        i += 28;
-        b2 += i;
-        m2 += i;
-        s2 += i;
-    }
-    if (b2 > 0)
-        lshift(b, b2);
-    if (s2 > 0)
-        lshift(s, s2);
-    if (k_check) {
-        if (cmp(b, s) < 0) {
-            k--;
-            multadd(b, 10, 0);    /* we botched the k estimate */
-            if (leftright)
-                multadd(mhi, 10, 0);
-            ilim = ilim1;
-        }
-    }
-    if (ilim <= 0 && roundingDecimalPlaces) {
-        if (ilim < 0)
-            goto noDigits;
-        multadd(s, 5, 0);
-        // For IEEE-754 unbiased rounding this check should be <=, such that 0.5 would flush to zero.
-        if (cmp(b, s) < 0)
-            goto noDigits;
-        goto oneDigit;
-    }
-    if (leftright) {
-        if (m2 > 0)
-            lshift(mhi, m2);
-
-        /* Compute mlo -- check for special case
-         * that d is a normalized power of 2.
-         */
-
-        mlo = mhi;
-        if (spec_case)
-            lshift(mhi, Log2P);
-
-        for (i = 1;;i++) {
-            dig = quorem(b, s) + '0';
-            /* Do we yet have the shortest decimal string
-             * that will round to d?
-             */
-            j = cmp(b, mlo);
-            diff(delta, s, mhi);
-            j1 = delta.sign ? 1 : cmp(b, delta);
-#ifdef DTOA_ROUND_BIASED
-            if (j < 0 || !j) {
-#else
-            // FIXME: ECMA-262 specifies that equidistant results round away from
-            // zero, which probably means we shouldn't be on the unbiased code path
-            // (the (word1(&u) & 1) clause is looking highly suspicious). I haven't
-            // yet understood this code well enough to make the call, but we should
-            // probably be enabling DTOA_ROUND_BIASED. I think the interesting corner
-            // case to understand is probably "Math.pow(0.5, 24).toString()".
-            // I believe this value is interesting because I think it is precisely
-            // representable in binary floating point, and its decimal representation
-            // has a single digit that Steele & White reduction can remove, with the
-            // value 5 (thus equidistant from the next numbers above and below).
-            // We produce the correct answer using either codepath, and I don't as
-            // yet understand why. :-)
-            if (!j1 && !(word1(&u) & 1)) {
-                if (dig == '9')
-                    goto round9up;
-                if (j > 0)
-                    dig++;
-                *str++ = dig;
-                goto ret;
-            }
-            if (j < 0 || (!j && !(word1(&u) & 1))) {
-#endif
-                if ((b.words()[0] || b.size() > 1) && (j1 > 0)) {
-                    lshift(b, 1);
-                    j1 = cmp(b, s);
-                    // For IEEE-754 round-to-even, this check should be (j1 > 0 || (!j1 && (dig & 1))),
-                    // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should
-                    // be rounded away from zero.
-                    if (j1 >= 0) {
-                        if (dig == '9')
-                            goto round9up;
-                        dig++;
-                    }
-                }
-                *str++ = dig;
-                goto ret;
-            }
-            if (j1 > 0) {
-                if (dig == '9') { /* possible if i == 1 */
-round9up:
-                    *str++ = '9';
-                    goto roundoff;
-                }
-                *str++ = dig + 1;
-                goto ret;
-            }
-            *str++ = dig;
-            if (i == ilim)
-                break;
-            multadd(b, 10, 0);
-            multadd(mlo, 10, 0);
-            multadd(mhi, 10, 0);
-        }
-    } else {
-        for (i = 1;; i++) {
-            *str++ = dig = quorem(b, s) + '0';
-            if (!b.words()[0] && b.size() <= 1)
-                goto ret;
-            if (i >= ilim)
-                break;
-            multadd(b, 10, 0);
-        }
-    }
-
-    /* Round off last digit */
-
-    lshift(b, 1);
-    j = cmp(b, s);
-    // For IEEE-754 round-to-even, this check should be (j > 0 || (!j && (dig & 1))),
-    // but ECMA-262 specifies that equidistant values (e.g. (.5).toFixed()) should
-    // be rounded away from zero.
-    if (j >= 0) {
-roundoff:
-        while (*--str == '9')
-            if (str == str0) {
-                k++;
-                *str++ = '1';
-                goto ret;
-            }
-        ++*str++;
-    } else {
-        while (*--str == '0') { }
-        str++;
-    }
-    goto ret;
-noDigits:
-    exponentOut = 0;
-    precisionOut = 1;
-    result[0] = '0';
-    result[1] = '\0';
-    return;
-oneDigit:
-    *str++ = '1';
-    k++;
-    goto ret;
-ret:
-    ASSERT(str > result);
-    *str = 0;
-    exponentOut = k;
-    precisionOut = str - result;
-}
-
-void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision)
-{
-    // flags are roundingNone, leftright.
-    dtoa<true, false, false, true>(result, dd, 0, sign, exponent, precision);
-}
-
-void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
-{
-    // flag is roundingSignificantFigures.
-    dtoa<false, true, false, false>(result, dd, ndigits, sign, exponent, precision);
-}
-
-void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision)
-{
-    // flag is roundingDecimalPlaces.
-    dtoa<false, false, true, false>(result, dd, ndigits, sign, exponent, precision);
-}
-
 const char* numberToString(double d, NumberToStringBuffer buffer)
 {
     double_conversion::StringBuilder builder(buffer, NumberToStringBufferLength);
diff --git a/third_party/WebKit/Source/wtf/dtoa.h b/third_party/WebKit/Source/wtf/dtoa.h
index fad2f7b..6d9cda2 100644
--- a/third_party/WebKit/Source/wtf/dtoa.h
+++ b/third_party/WebKit/Source/wtf/dtoa.h
@@ -28,20 +28,9 @@
 
 namespace WTF {
 
-class Mutex;
-
-extern Mutex* s_dtoaP5Mutex;
-
-typedef char DtoaBuffer[80];
-
-WTF_EXPORT void dtoa(DtoaBuffer result, double dd, bool& sign, int& exponent, unsigned& precision);
-WTF_EXPORT void dtoaRoundSF(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
-WTF_EXPORT void dtoaRoundDP(DtoaBuffer result, double dd, int ndigits, bool& sign, int& exponent, unsigned& precision);
-
 // Size = 80 for sizeof(DtoaBuffer) + some sign bits, decimal point, 'e', exponent digits.
 const unsigned NumberToStringBufferLength = 96;
 typedef char NumberToStringBuffer[NumberToStringBufferLength];
-typedef LChar NumberToLStringBuffer[NumberToStringBufferLength];
 
 WTF_EXPORT const char* numberToString(double, NumberToStringBuffer);
 WTF_EXPORT const char* numberToFixedPrecisionString(double, unsigned significantFigures, NumberToStringBuffer, bool truncateTrailingZeros = false);
@@ -73,7 +62,6 @@
 } // namespace WTF
 
 using WTF::NumberToStringBuffer;
-using WTF::NumberToLStringBuffer;
 using WTF::numberToString;
 using WTF::numberToFixedPrecisionString;
 using WTF::numberToFixedWidthString;
diff --git a/third_party/WebKit/public/web/WebRemoteFrameClient.h b/third_party/WebKit/public/web/WebRemoteFrameClient.h
index 980d713..2e62c35 100644
--- a/third_party/WebKit/public/web/WebRemoteFrameClient.h
+++ b/third_party/WebKit/public/web/WebRemoteFrameClient.h
@@ -34,9 +34,7 @@
 
     // Send initial drawing parameters to a child frame that is being rendered
     // out of process.
-    virtual void initializeChildFrame(
-        const WebRect& frameRect,
-        float deviceScaleFactor) { }
+    virtual void initializeChildFrame(float deviceScaleFactor) { }
 
     // A remote frame was asked to start a navigation.
     virtual void navigate(const WebURLRequest& request, bool shouldReplaceCurrentEntry) { }
diff --git a/third_party/kasko/BUILD.gn b/third_party/kasko/BUILD.gn
index 2d06fe09..6c1fc766 100644
--- a/third_party/kasko/BUILD.gn
+++ b/third_party/kasko/BUILD.gn
@@ -3,15 +3,7 @@
 # found in the LICENSE file.
 
 import("//build/buildflag_header.gni")
-import("//build/config/sanitizers/sanitizers.gni")
-
-declare_args() {
-  # Enable the Kasko crash reporter. Enabled by default on syzyasan build.
-  enable_kasko = is_syzyasan
-
-  # Enable the reporting of browser hangs with Kasko.
-  enable_kasko_hang_reports = false
-}
+import("//third_party/kasko/kasko.gni")
 
 # GYP version: target 'kasko_features' in third_party/kasko/kasko.gyp
 buildflag_header("kasko_features") {
@@ -19,6 +11,7 @@
   flags = [
     "ENABLE_KASKO=$enable_kasko",
     "ENABLE_KASKO_HANG_REPORTS=$enable_kasko_hang_reports",
+    "ENABLE_KASKO_FAILED_RDV_REPORTS=$enable_kasko_failed_rdv_reports",
   ]
 }
 
diff --git a/third_party/kasko/kasko.gni b/third_party/kasko/kasko.gni
new file mode 100644
index 0000000..fb394cc
--- /dev/null
+++ b/third_party/kasko/kasko.gni
@@ -0,0 +1,19 @@
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/config/sanitizers/sanitizers.gni")
+
+declare_args() {
+  # Enable the reporting of browser hangs with Kasko.
+  # TODO(pmonette): ensure hang reporting is disabled for syzyasan builds.
+  enable_kasko_hang_reports = false
+
+  # Enable the reporting of failed browser rendez-vous with Kasko.
+  # TODO(pmonette): ensure hang reporting is disabled for syzyasan builds.
+  enable_kasko_failed_rdv_reports = false
+}
+
+# Enable the Kasko crash reporter. Enabled by default on syzyasan build.
+enable_kasko =
+    is_syzyasan || enable_kasko_hang_reports || enable_kasko_failed_rdv_reports
diff --git a/third_party/kasko/kasko.gyp b/third_party/kasko/kasko.gyp
index 03fc566..4acbdb6 100644
--- a/third_party/kasko/kasko.gyp
+++ b/third_party/kasko/kasko.gyp
@@ -10,6 +10,7 @@
         'buildflag_flags': [
           'ENABLE_KASKO=<(kasko)',
           'ENABLE_KASKO_HANG_REPORTS=<(kasko_hang_reports)',
+          'ENABLE_KASKO_FAILED_RDV_REPORTS=<(kasko_failed_rdv_reports)',
         ],
       },
     },
diff --git a/third_party/qcms/README.chromium b/third_party/qcms/README.chromium
index db6a2b4a..930053a 100644
--- a/third_party/qcms/README.chromium
+++ b/third_party/qcms/README.chromium
@@ -147,6 +147,8 @@
    - https://code.google.com/p/chromium/issues/detail?id=580917
  - Update internal sRGB profile test report output
    - https://code.google.com/p/chromium/issues/detail?id=580917
+ - Add more internal sRGB profile tests
+   - https://code.google.com/p/chromium/issues/detail?id=580917
 
 For the Chromium changes, since the import, in a patch format run:
   git diff b8456f38 src
diff --git a/third_party/qcms/src/tests/qcms_test_internal_srgb.c b/third_party/qcms/src/tests/qcms_test_internal_srgb.c
index 12c9d8f..dac55f3 100644
--- a/third_party/qcms/src/tests/qcms_test_internal_srgb.c
+++ b/third_party/qcms/src/tests/qcms_test_internal_srgb.c
@@ -5,11 +5,16 @@
 #include "qcms.h"
 #include "qcms_test_util.h"
 
+#include <assert.h>
 #include <math.h> // sqrt
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
 
+#ifndef DISPLAY_DEVICE_PROFILE
+#define DISPLAY_DEVICE_PROFILE 0x6d6e7472 // 'mntr'
+#endif
+
 // D50 adapted color primaries of the internal sRGB color profile.
 static s15Fixed16Number sRGB_reference[3][3] = {
     { 0x06fa0, 0x06296, 0x024a0 }, // ( 0.436035, 0.385101, 0.143066 )
@@ -22,6 +27,14 @@
     0xf351, 0x10000, 0x116cc // ( 0.950455, 1.000000, 1.089050 )
 };
 
+static void check_profile_description(qcms_profile *profile)
+{
+    printf("Test profile description:\n");
+
+    const char* description = qcms_profile_get_description(profile);
+    printf("description=[%s]\n\n", description);
+}
+
 static void check_profile_pcs_white_point(const qcms_profile *profile)
 {
     float rX = s15Fixed16Number_to_float(profile->redColorant.X);
@@ -49,7 +62,7 @@
     float yerr = y - 0.358538597;
     float Yerr = Y - 1.000000000;
 
-    printf("D50 white point error = %.6f\n", (float)
+    printf("D50 white point error = %.6f\n\n", (float)
            sqrt((xerr * xerr) + (yerr * yerr) + (Yerr * Yerr)));
 }
 
@@ -103,9 +116,15 @@
         const char *out_path,
         const int force_software)
 {
-    qcms_profile *profile = qcms_profile_sRGB();
     s15Fixed16Number primary_error;
 
+    qcms_profile *profile = qcms_profile_sRGB();
+
+    assert(profile->class == DISPLAY_DEVICE_PROFILE);
+    assert(profile->rendering_intent == QCMS_INTENT_PERCEPTUAL);
+    assert(profile->color_space == RGB_SIGNATURE);
+    assert(profile->pcs == XYZ_SIGNATURE);
+
     if (qcms_profile_is_bogus(profile)) {
         fprintf(stderr, "Failure: the internal sRGB profile failed the bogus profile check\n");
         qcms_profile_release(profile);
@@ -122,6 +141,9 @@
     // Verify PCS white point correctness.
     check_profile_pcs_white_point(profile);
 
+    // Output profile description.
+    check_profile_description(profile);
+
     qcms_profile_release(profile);
     return primary_error;
 }
diff --git a/third_party/qcms/src/tests/qcms_test_munsell.c b/third_party/qcms/src/tests/qcms_test_munsell.c
index 9f1d7ef..8df3570e 100644
--- a/third_party/qcms/src/tests/qcms_test_munsell.c
+++ b/third_party/qcms/src/tests/qcms_test_munsell.c
@@ -93,6 +93,13 @@
     return round(sqrt((dr * dr) + (dg * dg) + (db * db)));
 }
 
+static qcms_profile* open_profile_from_path(const char *path)
+{
+    if (strcmp(path, "internal-srgb") != 0)
+        return qcms_profile_from_path(path);
+    return qcms_profile_sRGB();
+}
+
 static int qcms_test_munsell(size_t width,
         size_t height,
         int iterations,
@@ -124,7 +131,7 @@
         return EXIT_FAILURE;
     }
 
-    in_profile = qcms_profile_from_path(in_path);
+    in_profile = open_profile_from_path(in_path);
     if (!in_profile || invalid_rgb_color_profile(in_profile)) {
         fprintf(stderr, "Invalid input profile\n");
         return EXIT_FAILURE;
@@ -137,7 +144,7 @@
 
     printf("Input profile %s\n", in_profile->description);
 
-    out_profile = qcms_profile_from_path(out_path);
+    out_profile = open_profile_from_path(out_path);
     if (!out_profile || invalid_rgb_color_profile(out_profile)) {
         fprintf(stderr, "Invalid output profile\n");
         return EXIT_FAILURE;
@@ -159,6 +166,10 @@
         transform->transform_fn = qcms_transform_data_rgba_out_lut_precache;
     }
 
+    if (qcms_profile_match(in_profile, out_profile)) {
+        printf("Note: input / output profiles match\n");
+    }
+
     rmse = 0.0f;
 
     for (i = 0; i < 24; i++) {
diff --git a/tools/ipc_fuzzer/message_lib/all_messages.h b/tools/ipc_fuzzer/message_lib/all_messages.h
index cc60178..b9b8355 100644
--- a/tools/ipc_fuzzer/message_lib/all_messages.h
+++ b/tools/ipc_fuzzer/message_lib/all_messages.h
@@ -19,7 +19,6 @@
 #include "components/content_settings/content/common/content_settings_message_generator.h"
 #include "components/nacl/common/nacl_host_messages.h"
 #include "components/network_hints/common/network_hints_message_generator.h"
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
 #include "components/pdf/common/pdf_message_generator.h"
 #include "components/tracing/tracing_messages.h"
 #include "components/translate/content/common/translate_messages.h"
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 37f531e2..8033a8b 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -1567,11 +1567,14 @@
     # Removes dependencies on X11 and audio libraries for a containerized
     # build.
     'blimp': {
-      'gn_args': ('use_aura=true use_ozone=true use_alsa=false '
-                  'use_pulseaudio=false use_cups=false use_glib=false '
-                  'use_low_quality_image_interpolation=true'),
-      'gyp_defines': ('use_aura=1 use_ozone=1 use_alsa=0 '
-                      'use_pulseaudio=0 use_cups=0 use_glib=0'),
+      # This list must be kept in sync with the list in
+      # //build/args/blimp_engine.gn.
+      'gn_args': ('use_aura=true use_ozone=true ozone_auto_platforms=false '
+                  'ozone_platform="headless" ozone_platform_headless=true '
+                  'metrics_use_blimp=true '
+                  'use_low_quality_image_interpolation=true use_alsa=false '
+                  'use_pulseaudio=false use_cups=false use_glib=false'),
+      'gyp_defines': 'target_arch=unknown',
     },
 
     'cast': {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index f2ab34e..174c8e1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -68802,6 +68802,8 @@
   <int value="1113" label="INPUTMETHODPRIVATE_SHOWINPUTVIEW"/>
   <int value="1114" label="WALLPAPERPRIVATE_RECORDWALLPAPERUMA"/>
   <int value="1115" label="AUTOTESTPRIVATE_GETVISIBLENOTIFICATIONS"/>
+  <int value="1116" label="WEBRTCLOGGINGPRIVATE_STARTRTCEVENTLOGGING"/>
+  <int value="1117" label="WEBRTCLOGGINGPRIVATE_STOPRTCEVENTLOGGING"/>
 </enum>
 
 <enum name="ExtensionInstallCause" type="int">
@@ -75607,6 +75609,7 @@
   <int value="12" label="Non-invertible transform"/>
   <int value="13" label="Page based scrolling"/>
   <int value="14" label="Animating scroll on main thread"/>
+  <int value="15" label="Has sticky position objects"/>
 </enum>
 
 <enum name="MakeChromeDefaultResult" type="int">
diff --git a/tools/valgrind/memcheck/suppressions.txt b/tools/valgrind/memcheck/suppressions.txt
index 05484fa..277de33 100644
--- a/tools/valgrind/memcheck/suppressions.txt
+++ b/tools/valgrind/memcheck/suppressions.txt
@@ -2984,12 +2984,11 @@
    bug_576259_a
    Memcheck:Uninitialized
    fun:_ZN7GrGLGpu11bindTextureEiRK15GrTextureParamsbP11GrGLTexture
+   ...
    fun:_ZN7GrGLGpu12flushGLStateERK10GrPipelineRK20GrPrimitiveProcessor
    fun:_ZN7GrGLGpu6onDrawERK10GrPipelineRK20GrPrimitiveProcessorPK6GrMeshi
    fun:_ZN5GrGpu4drawERK10GrPipelineRK20GrPrimitiveProcessorPK6GrMeshi
    fun:_ZN13GrVertexBatch6onDrawEP17GrBatchFlushState
-   ...
-   fun:_ZN2cc17SingleThreadProxy36ScheduledActionDrawAndSwapIfPossibleEv
 }
 {
    bug_576259_b
@@ -3155,3 +3154,13 @@
    fun:_ZN3gin10Dictionary3SetIN4mojo6Handle*
    fun:_ZN4mojo3edk2js12_GLOBAL__N_114CreateDataPipe*
 }
+{
+   bug_602964
+   Memcheck:Leak
+   fun:_Znw*
+   fun:_ZN4base4BindIMNS_12_GLOBAL__N_121PostTaskAndReplyRelayEFvvEJNS_8internal17UnretainedWrapper*
+   fun:_ZN4base8internal20PostTaskAndReplyImpl16PostTaskAndReplyERKN15tracked_objects8LocationERKNS*
+   fun:_ZN4base10TaskRunner16PostTaskAndReplyERKN15tracked_objects8LocationERKNS_8CallbackIFvvELNS*
+   fun:_ZN4base26PostTaskAndReplyWithResultIN3net20WifiPHYLayerProtocolES2_EEbPNS*
+   fun:_ZN7metrics22NetworkMetricsProvider25ProbeWifiPHYLayerProtocolEv
+}
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 20b75f2..21eecf0b 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -54,8 +54,6 @@
     "keycodes/keyboard_code_conversion_win.cc",
     "keycodes/keyboard_code_conversion_win.h",
     "keycodes/keyboard_codes.h",
-    "latency_info.cc",
-    "latency_info.h",
   ]
 
   defines = [ "EVENTS_BASE_IMPLEMENTATION" ]
@@ -151,6 +149,7 @@
     "//skia",
     "//ui/gfx",
     "//ui/gfx/geometry",
+    "//ui/latency_info",
   ]
 
   if (use_x11) {
@@ -368,7 +367,6 @@
     "keycodes/dom/keycode_converter_unittest.cc",
     "keycodes/keyboard_code_conversion_unittest.cc",
     "keycodes/platform_key_map_win_unittest.cc",
-    "latency_info_unittest.cc",
     "platform/platform_event_source_unittest.cc",
     "scoped_target_handler_unittest.cc",
     "win/event_utils_win_unittest.cc",
@@ -389,6 +387,7 @@
     "//ui/events/devices",
     "//ui/events/platform",
     "//ui/gfx:test_support",
+    "//ui/latency_info",
   ]
 
   if (!is_ios) {
@@ -396,7 +395,6 @@
       "blink/input_handler_proxy_unittest.cc",
       "blink/input_scroll_elasticity_controller_unittest.cc",
       "gestures/blink/web_gesture_curve_impl_unittest.cc",
-      "ipc/latency_info_param_traits_unittest.cc",
     ]
     deps += [
       "//cc",
@@ -404,7 +402,6 @@
       "//third_party/WebKit/public:blink_headers",
       "//ui/events/blink",
       "//ui/events/gestures/blink",
-      "//ui/events/ipc",
     ]
   }
 
diff --git a/ui/events/DEPS b/ui/events/DEPS
index b273ae3..8a18605 100644
--- a/ui/events/DEPS
+++ b/ui/events/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+ui/gfx",
+  "+ui/latency_info",
 ]
diff --git a/ui/events/OWNERS b/ui/events/OWNERS
index f14df80fd..1c0edbda 100644
--- a/ui/events/OWNERS
+++ b/ui/events/OWNERS
@@ -1,7 +1,4 @@
 sadrul@chromium.org
-per-file latency_info*=tdresser@chromium.org
-per-file latency_info*=jbauman@chromium.org
-per-file latency_info*=miletus@chromium.org
 
 # If you're doing structural changes get a review from one of the OWNERS.
 per-file *.gyp*=*
diff --git a/ui/events/blink/events_blink.gyp b/ui/events/blink/events_blink.gyp
index 8b1b8fa..c347d9b 100644
--- a/ui/events/blink/events_blink.gyp
+++ b/ui/events/blink/events_blink.gyp
@@ -15,6 +15,7 @@
         '../../../cc/cc.gyp:cc',
         '../../../third_party/WebKit/public/blink_headers.gyp:blink_headers',
         '../../gfx/gfx.gyp:gfx_geometry',
+        '../../latency_info/latency_info.gyp:latency_info',
         '../events.gyp:events',
         '../events.gyp:gesture_detection',
       ],
@@ -31,4 +32,4 @@
       ],
     },
   ],
-}
\ No newline at end of file
+}
diff --git a/ui/events/blink/input_handler_proxy.cc b/ui/events/blink/input_handler_proxy.cc
index 2d9eefb..bc494871 100644
--- a/ui/events/blink/input_handler_proxy.cc
+++ b/ui/events/blink/input_handler_proxy.cc
@@ -20,8 +20,8 @@
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/blink/input_handler_proxy_client.h"
 #include "ui/events/blink/input_scroll_elasticity_controller.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/point_conversions.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebFloatPoint;
 using blink::WebFloatSize;
diff --git a/ui/events/blink/input_handler_proxy_unittest.cc b/ui/events/blink/input_handler_proxy_unittest.cc
index 2ef91cd..729029b 100644
--- a/ui/events/blink/input_handler_proxy_unittest.cc
+++ b/ui/events/blink/input_handler_proxy_unittest.cc
@@ -18,9 +18,9 @@
 #include "third_party/WebKit/public/platform/WebPoint.h"
 #include "third_party/WebKit/public/web/WebInputEvent.h"
 #include "ui/events/blink/input_handler_proxy_client.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/scroll_offset.h"
 #include "ui/gfx/geometry/size_f.h"
+#include "ui/latency_info/latency_info.h"
 
 using blink::WebActiveWheelFlingParameters;
 using blink::WebFloatPoint;
diff --git a/ui/events/event.h b/ui/events/event.h
index 5c1b108..07416945 100644
--- a/ui/events/event.h
+++ b/ui/events/event.h
@@ -20,9 +20,9 @@
 #include "ui/events/gestures/gesture_types.h"
 #include "ui/events/keycodes/dom/dom_key.h"
 #include "ui/events/keycodes/keyboard_codes.h"
-#include "ui/events/latency_info.h"
 #include "ui/gfx/geometry/point.h"
 #include "ui/gfx/geometry/point_conversions.h"
+#include "ui/latency_info/latency_info.h"
 
 namespace gfx {
 class Transform;
diff --git a/ui/events/events.gyp b/ui/events/events.gyp
index c8d994f..8c814d3 100644
--- a/ui/events/events.gyp
+++ b/ui/events/events.gyp
@@ -66,8 +66,6 @@
         'keycodes/keyboard_code_conversion_x.cc',
         'keycodes/keyboard_code_conversion_x.h',
         'keycodes/keyboard_codes.h',
-        'latency_info.cc',
-        'latency_info.h',
         'x/keysym_to_unicode.cc',
         'x/keysym_to_unicode.h',
       ],
@@ -100,6 +98,7 @@
         '<(DEPTH)/skia/skia.gyp:skia',
         '../gfx/gfx.gyp:gfx',
         '../gfx/gfx.gyp:gfx_geometry',
+        '../latency_info/latency_info.gyp:latency_info',
         'dom_keycode_converter',
         'events_base',
         'gesture_detection',
@@ -301,24 +300,6 @@
       ],
     },
     {
-      # GN version: //ui/events/ipc:events_ipc
-      'target_name': 'events_ipc',
-      'type': '<(component)',
-      'dependencies': [
-        '<(DEPTH)/base/base.gyp:base',
-        '<(DEPTH)/ipc/ipc.gyp:ipc',
-        'events_base',
-      ],
-      'defines': [
-        'EVENTS_IPC_IMPLEMENTATION',
-      ],
-      'sources': [
-        'ipc/latency_info_param_traits.cc',
-        'ipc/latency_info_param_traits.h',
-        'ipc/latency_info_param_traits_macros.h',
-      ],
-    },
-    {
       # GN version: //ui/events:test_support
       'target_name': 'events_test_support',
       'type': 'static_library',
diff --git a/ui/events/events_unittests.gyp b/ui/events/events_unittests.gyp
index f5a5d01c..0665b33 100644
--- a/ui/events/events_unittests.gyp
+++ b/ui/events/events_unittests.gyp
@@ -26,7 +26,6 @@
         'events.gyp:dom_keycode_converter',
         'events.gyp:events',
         'events.gyp:events_base',
-        'events.gyp:events_ipc',
         'events.gyp:events_test_support',
         'events.gyp:gesture_detection',
         'events.gyp:gestures_blink',
@@ -54,11 +53,9 @@
         'gestures/fling_curve_unittest.cc',
         'gestures/gesture_provider_aura_unittest.cc',
         'gestures/motion_event_aura_unittest.cc',
-        'ipc/latency_info_param_traits_unittest.cc',
         'keycodes/dom/keycode_converter_unittest.cc',
         'keycodes/keyboard_code_conversion_unittest.cc',
         'keycodes/platform_key_map_win_unittest.cc',
-        'latency_info_unittest.cc',
         'platform/platform_event_source_unittest.cc',
         'scoped_target_handler_unittest.cc',
         'win/event_utils_win_unittest.cc',
diff --git a/ui/events/ipc/OWNERS b/ui/events/ipc/OWNERS
deleted file mode 100644
index 6732300..0000000
--- a/ui/events/ipc/OWNERS
+++ /dev/null
@@ -1,12 +0,0 @@
-set noparent
-dcheng@chromium.org
-inferno@chromium.org
-jln@chromium.org
-jschuh@chromium.org
-kenrb@chromium.org
-nasko@chromium.org
-palmer@chromium.org
-tsepez@chromium.org
-
-per-file *.gyp*=*
-per-file BUILD.gn=*
diff --git a/ui/events/ipc/events_ipc_export.h b/ui/events/ipc/events_ipc_export.h
deleted file mode 100644
index a02d669..0000000
--- a/ui/events/ipc/events_ipc_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright (c) 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_EVENTS_IPC_EXPORT_H_
-#define UI_EVENTS_EVENTS_IPC_EXPORT_H_
-
-#if defined(COMPONENT_BUILD)
-#if defined(WIN32)
-
-#if defined(EVENTS_IPC_IMPLEMENTATION)
-#define EVENTS_IPC_EXPORT __declspec(dllexport)
-#else
-#define EVENTS_IPC_EXPORT __declspec(dllimport)
-#endif  // defined(EVENTS_IPC_IMPLEMENTATION)
-
-#else  // defined(WIN32)
-#if defined(EVENTS_IPC_IMPLEMENTATION)
-#define EVENTS_IPC_EXPORT __attribute__((visibility("default")))
-#else
-#define EVENTS_IPC_EXPORT
-#endif
-#endif
-
-#else  // defined(COMPONENT_BUILD)
-#define EVENTS_IPC_EXPORT
-#endif
-
-#endif  // UI_EVENTS_EVENTS_IPC_EXPORT_H_
diff --git a/ui/events/ipc/latency_info_param_traits.h b/ui/events/ipc/latency_info_param_traits.h
deleted file mode 100644
index 9e11104..0000000
--- a/ui/events/ipc/latency_info_param_traits.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
-#define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
-
-#include "ui/events/ipc/events_ipc_export.h"
-#include "ui/events/latency_info.h"
-
-namespace IPC {
-template <>
-struct EVENTS_IPC_EXPORT ParamTraits<ui::LatencyInfo> {
-  typedef ui::LatencyInfo param_type;
-  static void Write(base::Pickle* m, const param_type& p);
-  static bool Read(const base::Pickle* m,
-                   base::PickleIterator* iter,
-                   param_type* p);
-  static void Log(const param_type& p, std::string* l);
-};
-}  // namespace IPC
-
-#endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_H_
diff --git a/ui/gfx/transform.cc b/ui/gfx/transform.cc
index a0445e4..88f0942 100644
--- a/ui/gfx/transform.cc
+++ b/ui/gfx/transform.cc
@@ -407,6 +407,11 @@
   TransformPointInternal(matrix_, point);
 }
 
+void Transform::TransformVector(Vector3dF* vector) const {
+  DCHECK(vector);
+  TransformVectorInternal(matrix_, vector);
+}
+
 bool Transform::TransformPointReverse(Point* point) const {
   DCHECK(point);
 
@@ -520,6 +525,22 @@
   }
 }
 
+void Transform::TransformVectorInternal(const SkMatrix44& xform,
+                                        Vector3dF* vector) const {
+  if (xform.isIdentity())
+    return;
+
+  SkMScalar p[4] = {SkFloatToMScalar(vector->x()),
+                    SkFloatToMScalar(vector->y()),
+                    SkFloatToMScalar(vector->z()), 0};
+
+  xform.mapMScalars(p);
+
+  vector->set_x(p[0]);
+  vector->set_y(p[1]);
+  vector->set_z(p[2]);
+}
+
 void Transform::TransformPointInternal(const SkMatrix44& xform,
                                        Point* point) const {
   if (xform.isIdentity())
diff --git a/ui/gfx/transform.h b/ui/gfx/transform.h
index 75c4797..5bd74b51 100644
--- a/ui/gfx/transform.h
+++ b/ui/gfx/transform.h
@@ -198,6 +198,9 @@
   // Applies the transformation to the point.
   void TransformPoint(Point* point) const;
 
+  // Applies the transformation to the vector.
+  void TransformVector(Vector3dF* vector) const;
+
   // Applies the reverse transformation on the point. Returns true if the
   // transformation can be inverted.
   bool TransformPointReverse(Point3F* point) const;
@@ -266,6 +269,9 @@
   void TransformPointInternal(const SkMatrix44& xform,
                               Point3F* point) const;
 
+  void TransformVectorInternal(const SkMatrix44& xform,
+                               Vector3dF* vector) const;
+
   SkMatrix44 matrix_;
 
   // copy/assign are allowed.
diff --git a/ui/gl/gl_surface_ozone.cc b/ui/gl/gl_surface_ozone.cc
index cb7c8bbc..d4d2fe1 100644
--- a/ui/gl/gl_surface_ozone.cc
+++ b/ui/gl/gl_surface_ozone.cc
@@ -603,9 +603,11 @@
   }
 
   if (!was_current) {
-    previous_context->MakeCurrent(previous_surface.get());
-  } else {
-    context_->ReleaseCurrent(this);
+    if (previous_context) {
+      previous_context->MakeCurrent(previous_surface.get());
+    } else {
+      context_->ReleaseCurrent(this);
+    }
   }
 }
 
diff --git a/ui/latency_info/BUILD.gn b/ui/latency_info/BUILD.gn
new file mode 100644
index 0000000..ad8f8c152
--- /dev/null
+++ b/ui/latency_info/BUILD.gn
@@ -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.
+
+import("//testing/test.gni")
+
+component("latency_info") {
+  sources = [
+    "latency_info.cc",
+    "latency_info.h",
+    "latency_info_export.h",
+  ]
+
+  defines = [ "LATENCY_INFO_IMPLEMENTATION" ]
+
+  deps = [
+    "//base",
+  ]
+}
+
+test("latency_info_unittests") {
+  sources = [
+    "latency_info_unittest.cc",
+  ]
+
+  deps = [
+    ":latency_info",
+    "//base",
+    "//base/test:run_all_unittests",
+    "//base/test:test_support",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  if (!is_ios) {
+    sources += [ "ipc/latency_info_param_traits_unittest.cc" ]
+    deps += [
+      "//ipc:test_support",
+      "//ui/latency_info/ipc",
+    ]
+  }
+}
diff --git a/ui/latency_info/OWNERS b/ui/latency_info/OWNERS
new file mode 100644
index 0000000..b29cc1a
--- /dev/null
+++ b/ui/latency_info/OWNERS
@@ -0,0 +1 @@
+tdresser@chromium.org
diff --git a/ui/events/ipc/BUILD.gn b/ui/latency_info/ipc/BUILD.gn
similarity index 68%
rename from ui/events/ipc/BUILD.gn
rename to ui/latency_info/ipc/BUILD.gn
index b6ccbf5..411305d 100644
--- a/ui/events/ipc/BUILD.gn
+++ b/ui/latency_info/ipc/BUILD.gn
@@ -2,21 +2,23 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-import("//build/config/ui.gni")
-
 component("ipc") {
-  output_name = "events_ipc"
+  output_name = "latency_info_ipc"
   sources = [
+    "latency_info_ipc_export.h",
     "latency_info_param_traits.cc",
     "latency_info_param_traits.h",
     "latency_info_param_traits_macros.h",
   ]
 
-  defines = [ "EVENTS_IPC_IMPLEMENTATION" ]
+  defines = [ "LATENCY_INFO_IPC_IMPLEMENTATION" ]
+
+  public_deps = [
+    "//ui/latency_info",
+  ]
 
   deps = [
     "//base",
     "//ipc",
-    "//ui/events:events_base",
   ]
 }
diff --git a/ui/latency_info/ipc/OWNERS b/ui/latency_info/ipc/OWNERS
new file mode 100644
index 0000000..107c401
--- /dev/null
+++ b/ui/latency_info/ipc/OWNERS
@@ -0,0 +1,13 @@
+# Changes to IPCs require a security review to avoid introducing
+# new sandbox escapes.
+set noparent
+dcheng@chromium.org
+inferno@chromium.org
+jln@chromium.org
+jschuh@chromium.org
+kenrb@chromium.org
+mkwst@chromium.org
+nasko@chromium.org
+palmer@chromium.org
+tsepez@chromium.org
+wfh@chromium.org
diff --git a/ui/latency_info/ipc/latency_info_ipc_export.h b/ui/latency_info/ipc/latency_info_ipc_export.h
new file mode 100644
index 0000000..cf80d5fd
--- /dev/null
+++ b/ui/latency_info/ipc/latency_info_ipc_export.h
@@ -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.
+
+#ifndef UI_LATENCY_INFO_LATENCY_INFO_IPC_EXPORT_H_
+#define UI_LATENCY_INFO_LATENCY_INFO_IPC_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(LATENCY_INFO_IPC_IMPLEMENTATION)
+#define LATENCY_INFO_IPC_EXPORT __declspec(dllexport)
+#else
+#define LATENCY_INFO_IPC_EXPORT __declspec(dllimport)
+#endif  // defined(LATENCY_INFO_IPC_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(LATENCY_INFO_IPC_IMPLEMENTATION)
+#define LATENCY_INFO_IPC_EXPORT __attribute__((visibility("default")))
+#else
+#define LATENCY_INFO_IPC_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define LATENCY_INFO_IPC_EXPORT
+#endif
+
+#endif  // UI_LATENCY_INFO_LATENCY_INFO_IPC_EXPORT_H_
diff --git a/ui/events/ipc/latency_info_param_traits.cc b/ui/latency_info/ipc/latency_info_param_traits.cc
similarity index 77%
rename from ui/events/ipc/latency_info_param_traits.cc
rename to ui/latency_info/ipc/latency_info_param_traits.cc
index a4723074..22785fcf 100644
--- a/ui/events/ipc/latency_info_param_traits.cc
+++ b/ui/latency_info/ipc/latency_info_param_traits.cc
@@ -2,31 +2,31 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/events/ipc/latency_info_param_traits_macros.h"
+#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
 
 // Generate param traits write methods.
 #include "ipc/param_traits_write_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/events/ipc/latency_info_param_traits_macros.h"
+#undef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Generate param traits read methods.
 #include "ipc/param_traits_read_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/events/ipc/latency_info_param_traits_macros.h"
+#undef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Generate param traits log methods.
 #include "ipc/param_traits_log_macros.h"
 namespace IPC {
-#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/events/ipc/latency_info_param_traits_macros.h"
+#undef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Implemetation for ParamTraits<ui::LatencyInfo>.
-#include "ui/events/ipc/latency_info_param_traits.h"
+#include "ui/latency_info/ipc/latency_info_param_traits.h"
 
 namespace IPC {
 void ParamTraits<ui::LatencyInfo>::Write(base::Pickle* m, const param_type& p) {
@@ -54,7 +54,7 @@
     return false;
   for (size_t i = 0; i < input_coordinates_size; i++) {
     if (!ReadParam(m, iter, &input_coordinates))
-        return false;
+      return false;
     if (!p->AddInputCoordinate(input_coordinates))
       return false;
   }
@@ -67,8 +67,7 @@
   return true;
 }
 
-void ParamTraits<ui::LatencyInfo>::Log(const param_type& p,
-                                       std::string* l) {
+void ParamTraits<ui::LatencyInfo>::Log(const param_type& p, std::string* l) {
   LogParam(p.trace_name_, l);
   l->append(" ");
   LogParam(p.latency_components_, l);
diff --git a/ui/latency_info/ipc/latency_info_param_traits.h b/ui/latency_info/ipc/latency_info_param_traits.h
new file mode 100644
index 0000000..4bfdc6e
--- /dev/null
+++ b/ui/latency_info/ipc/latency_info_param_traits.h
@@ -0,0 +1,23 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+#define UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_H_
+
+#include "ui/latency_info/ipc/latency_info_ipc_export.h"
+#include "ui/latency_info/latency_info.h"
+
+namespace IPC {
+template <>
+struct LATENCY_INFO_IPC_EXPORT ParamTraits<ui::LatencyInfo> {
+  typedef ui::LatencyInfo param_type;
+  static void Write(base::Pickle* m, const param_type& p);
+  static bool Read(const base::Pickle* m,
+                   base::PickleIterator* iter,
+                   param_type* p);
+  static void Log(const param_type& p, std::string* l);
+};
+}  // namespace IPC
+
+#endif  // UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_H_
diff --git a/ui/events/ipc/latency_info_param_traits_macros.h b/ui/latency_info/ipc/latency_info_param_traits_macros.h
similarity index 66%
rename from ui/events/ipc/latency_info_param_traits_macros.h
rename to ui/latency_info/ipc/latency_info_param_traits_macros.h
index 40bf738..2539d92 100644
--- a/ui/events/ipc/latency_info_param_traits_macros.h
+++ b/ui/latency_info/ipc/latency_info_param_traits_macros.h
@@ -2,15 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#ifndef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#define UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
 
 #include "ipc/ipc_message_macros.h"
-#include "ui/events/ipc/events_ipc_export.h"
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/ipc/latency_info_ipc_export.h"
+#include "ui/latency_info/latency_info.h"
 
 #undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT EVENTS_IPC_EXPORT
+#define IPC_MESSAGE_EXPORT LATENCY_INFO_IPC_EXPORT
 
 IPC_ENUM_TRAITS_MAX_VALUE(ui::LatencyComponentType,
                           ui::LATENCY_COMPONENT_TYPE_LAST)
@@ -26,4 +26,4 @@
   IPC_STRUCT_TRAITS_MEMBER(y)
 IPC_STRUCT_TRAITS_END()
 
-#endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#endif  // UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
diff --git a/ui/events/ipc/latency_info_param_traits_unittest.cc b/ui/latency_info/ipc/latency_info_param_traits_unittest.cc
similarity index 84%
rename from ui/events/ipc/latency_info_param_traits_unittest.cc
rename to ui/latency_info/ipc/latency_info_param_traits_unittest.cc
index 69224dac..4a1f8dc 100644
--- a/ui/events/ipc/latency_info_param_traits_unittest.cc
+++ b/ui/latency_info/ipc/latency_info_param_traits_unittest.cc
@@ -7,8 +7,8 @@
 
 #include "ipc/ipc_message_macros.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/events/ipc/latency_info_param_traits.h"
-#include "ui/events/ipc/latency_info_param_traits_macros.h"
+#include "ui/latency_info/ipc/latency_info_param_traits.h"
+#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
 
 namespace ui {
 
@@ -20,13 +20,13 @@
   latency.AddLatencyNumber(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1234, 100);
   latency.AddLatencyNumber(INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT,
                            1234, 0);
-  EXPECT_TRUE(latency.AddInputCoordinate(
-      LatencyInfo::InputCoordinate(100, 200)));
-  EXPECT_TRUE(latency.AddInputCoordinate(
-      LatencyInfo::InputCoordinate(101, 201)));
+  EXPECT_TRUE(
+      latency.AddInputCoordinate(LatencyInfo::InputCoordinate(100, 200)));
+  EXPECT_TRUE(
+      latency.AddInputCoordinate(LatencyInfo::InputCoordinate(101, 201)));
   // Up to 2 InputCoordinate is allowed.
-  EXPECT_FALSE(latency.AddInputCoordinate(
-      LatencyInfo::InputCoordinate(102, 202)));
+  EXPECT_FALSE(
+      latency.AddInputCoordinate(LatencyInfo::InputCoordinate(102, 202)));
 
   EXPECT_EQ(100, latency.trace_id());
   EXPECT_TRUE(latency.terminated());
@@ -48,13 +48,11 @@
               output.input_coordinates()[i].y);
   }
 
-  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
-                                 1234,
+  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 1234,
                                  nullptr));
 
   LatencyInfo::LatencyComponent rwh_comp;
-  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT,
-                                 1234,
+  EXPECT_TRUE(output.FindLatency(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT, 1234,
                                  &rwh_comp));
   EXPECT_EQ(100, rwh_comp.sequence_number);
   EXPECT_EQ(1u, rwh_comp.event_count);
diff --git a/ui/events/latency_info.cc b/ui/latency_info/latency_info.cc
similarity index 81%
rename from ui/events/latency_info.cc
rename to ui/latency_info/latency_info.cc
index b5d9954..66e3748 100644
--- a/ui/events/latency_info.cc
+++ b/ui/latency_info/latency_info.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 #include <stddef.h>
 
@@ -20,7 +20,9 @@
 const size_t kMaxLatencyInfoNumber = 100;
 
 const char* GetComponentName(ui::LatencyComponentType type) {
-#define CASE_TYPE(t) case ui::t:  return #t
+#define CASE_TYPE(t) \
+  case ui::t:        \
+    return #t
   switch (type) {
     CASE_TYPE(INPUT_EVENT_LATENCY_BEGIN_RWH_COMPONENT);
     CASE_TYPE(LATENCY_BEGIN_SCROLL_LISTENER_UPDATE_MAIN_COMPONENT);
@@ -104,8 +106,7 @@
       new LatencyInfoTracedValue(value.release()));
 }
 
-LatencyInfoTracedValue::~LatencyInfoTracedValue() {
-}
+LatencyInfoTracedValue::~LatencyInfoTracedValue() {}
 
 void LatencyInfoTracedValue::AppendAsTraceFormat(std::string* out) const {
   std::string tmp;
@@ -114,32 +115,28 @@
 }
 
 LatencyInfoTracedValue::LatencyInfoTracedValue(base::Value* value)
-    : value_(value) {
-}
+    : value_(value) {}
 
 const char kTraceCategoriesForAsyncEvents[] = "benchmark,latencyInfo";
 
 struct LatencyInfoEnabledInitializer {
-  LatencyInfoEnabledInitializer() :
-      latency_info_enabled(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
-          kTraceCategoriesForAsyncEvents)) {
-  }
+  LatencyInfoEnabledInitializer()
+      : latency_info_enabled(TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(
+            kTraceCategoriesForAsyncEvents)) {}
 
   const unsigned char* latency_info_enabled;
 };
 
 static base::LazyInstance<LatencyInfoEnabledInitializer>::Leaky
-  g_latency_info_enabled = LAZY_INSTANCE_INITIALIZER;
+    g_latency_info_enabled = LAZY_INSTANCE_INITIALIZER;
 
 }  // namespace
 
 namespace ui {
 
-LatencyInfo::InputCoordinate::InputCoordinate() : x(0), y(0) {
-}
+LatencyInfo::InputCoordinate::InputCoordinate() : x(0), y(0) {}
 
-LatencyInfo::InputCoordinate::InputCoordinate(float x, float y) : x(x), y(y) {
-}
+LatencyInfo::InputCoordinate::InputCoordinate(float x, float y) : x(x), y(y) {}
 
 LatencyInfo::LatencyInfo()
     : input_coordinates_size_(0),
@@ -162,8 +159,7 @@
     LOG(ERROR) << referring_msg << ", LatencyInfo vector size "
                << latency_info.size() << " is too big.";
     TRACE_EVENT_INSTANT1("input,benchmark", "LatencyInfo::Verify Fails",
-                         TRACE_EVENT_SCOPE_GLOBAL,
-                         "size", latency_info.size());
+                         TRACE_EVENT_SCOPE_GLOBAL, "size", latency_info.size());
     return false;
   }
   return true;
@@ -173,11 +169,9 @@
                                   LatencyComponentType type) {
   for (const auto& lc : other.latency_components()) {
     if (lc.first.first == type) {
-      AddLatencyNumberWithTimestamp(lc.first.first,
-                                    lc.first.second,
-                                    lc.second.sequence_number,
-                                    lc.second.event_time,
-                                    lc.second.event_count);
+      AddLatencyNumberWithTimestamp(
+          lc.first.first, lc.first.second, lc.second.sequence_number,
+          lc.second.event_time, lc.second.event_count);
     }
   }
 }
@@ -185,11 +179,9 @@
 void LatencyInfo::AddNewLatencyFrom(const LatencyInfo& other) {
   for (const auto& lc : other.latency_components()) {
     if (!FindLatency(lc.first.first, lc.first.second, NULL)) {
-      AddLatencyNumberWithTimestamp(lc.first.first,
-                                    lc.first.second,
-                                    lc.second.sequence_number,
-                                    lc.second.event_time,
-                                    lc.second.event_count);
+      AddLatencyNumberWithTimestamp(
+          lc.first.first, lc.first.second, lc.second.sequence_number,
+          lc.second.event_time, lc.second.event_count);
     }
   }
 }
@@ -243,12 +235,9 @@
       // not when we actually issue the ASYNC_BEGIN trace event.
       LatencyComponent begin_component;
       int64_t ts = 0;
-      if (FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT,
-                      0,
+      if (FindLatency(INPUT_EVENT_LATENCY_ORIGINAL_COMPONENT, 0,
                       &begin_component) ||
-          FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT,
-                      0,
-                      &begin_component)) {
+          FindLatency(INPUT_EVENT_LATENCY_UI_COMPONENT, 0, &begin_component)) {
         ts = begin_component.event_time.ToInternalValue();
       } else {
         ts = base::TimeTicks::Now().ToInternalValue();
@@ -262,17 +251,13 @@
       }
 
       TRACE_EVENT_COPY_ASYNC_BEGIN_WITH_TIMESTAMP0(
-          kTraceCategoriesForAsyncEvents,
-          trace_name_.c_str(),
-          TRACE_ID_DONT_MANGLE(trace_id_),
-          ts);
+          kTraceCategoriesForAsyncEvents, trace_name_.c_str(),
+          TRACE_ID_DONT_MANGLE(trace_id_), ts);
     }
 
-    TRACE_EVENT_WITH_FLOW1("input,benchmark",
-                           "LatencyInfo.Flow",
+    TRACE_EVENT_WITH_FLOW1("input,benchmark", "LatencyInfo.Flow",
                            TRACE_ID_DONT_MANGLE(trace_id_),
-                           TRACE_EVENT_FLAG_FLOW_OUT,
-                           "trace_id", trace_id_);
+                           TRACE_EVENT_FLAG_FLOW_OUT, "trace_id", trace_id_);
   }
 
   LatencyMap::key_type key = std::make_pair(component, id);
@@ -281,15 +266,15 @@
     LatencyComponent info = {component_sequence_number, time, event_count};
     latency_components_[key] = info;
   } else {
-    it->second.sequence_number = std::max(component_sequence_number,
-                                          it->second.sequence_number);
+    it->second.sequence_number =
+        std::max(component_sequence_number, it->second.sequence_number);
     uint32_t new_count = event_count + it->second.event_count;
     if (event_count > 0 && new_count != 0) {
       // Do a weighted average, so that the new event_time is the average of
       // the times of events currently in this structure with the time passed
       // into this method.
-      it->second.event_time += (time - it->second.event_time) * event_count /
-          new_count;
+      it->second.event_time +=
+          (time - it->second.event_time) * event_count / new_count;
       it->second.event_count = new_count;
     }
   }
@@ -300,15 +285,13 @@
     terminated_ = true;
 
     if (*latency_info_enabled) {
-      TRACE_EVENT_COPY_ASYNC_END2(kTraceCategoriesForAsyncEvents,
-                                  trace_name_.c_str(),
-                                  TRACE_ID_DONT_MANGLE(trace_id_),
-                                  "data", AsTraceableData(),
-                                  "coordinates", CoordinatesAsTraceableData());
+      TRACE_EVENT_COPY_ASYNC_END2(
+          kTraceCategoriesForAsyncEvents, trace_name_.c_str(),
+          TRACE_ID_DONT_MANGLE(trace_id_), "data", AsTraceableData(),
+          "coordinates", CoordinatesAsTraceableData());
     }
 
-    TRACE_EVENT_WITH_FLOW0("input,benchmark",
-                           "LatencyInfo.Flow",
+    TRACE_EVENT_WITH_FLOW0("input,benchmark", "LatencyInfo.Flow",
                            TRACE_ID_DONT_MANGLE(trace_id_),
                            TRACE_EVENT_FLAG_FLOW_IN);
   }
@@ -323,11 +306,9 @@
         new base::DictionaryValue());
     component_info->SetDouble("comp_id", static_cast<double>(lc.first.second));
     component_info->SetDouble(
-        "time",
-        static_cast<double>(lc.second.event_time.ToInternalValue()));
+        "time", static_cast<double>(lc.second.event_time.ToInternalValue()));
     component_info->SetDouble("count", lc.second.event_count);
-    component_info->SetDouble("sequence_number",
-                              lc.second.sequence_number);
+    component_info->SetDouble("sequence_number", lc.second.sequence_number);
     record_data->Set(GetComponentName(lc.first.first),
                      std::move(component_info));
   }
@@ -351,8 +332,8 @@
 bool LatencyInfo::FindLatency(LatencyComponentType type,
                               int64_t id,
                               LatencyComponent* output) const {
-  LatencyMap::const_iterator it = latency_components_.find(
-      std::make_pair(type, id));
+  LatencyMap::const_iterator it =
+      latency_components_.find(std::make_pair(type, id));
   if (it == latency_components_.end())
     return false;
   if (output)
diff --git a/ui/events/latency_info.dot b/ui/latency_info/latency_info.dot
similarity index 100%
rename from ui/events/latency_info.dot
rename to ui/latency_info/latency_info.dot
diff --git a/ui/latency_info/latency_info.gyp b/ui/latency_info/latency_info.gyp
new file mode 100644
index 0000000..ce7f05f
--- /dev/null
+++ b/ui/latency_info/latency_info.gyp
@@ -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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      # GN version: //ui/latency_info:latency_info
+      'target_name': 'latency_info',
+      'type': '<(component)',
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base',
+      ],
+      'defines': [
+        'LATENCY_INFO_IMPLEMENTATION',
+      ],
+      'sources': [
+        'latency_info.cc',
+        'latency_info.h',
+        'latency_info_export.h',
+      ],
+    },
+    {
+      # GN version: //ui/latency_info/ipc:latency_info_ipc
+      'target_name': 'latency_info_ipc',
+      'type': '<(component)',
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/ipc/ipc.gyp:ipc',
+        'latency_info',
+      ],
+      'defines': [
+        'LATENCY_INFO_IPC_IMPLEMENTATION',
+      ],
+      'sources': [
+        'ipc/latency_info_ipc_export.h',
+        'ipc/latency_info_param_traits.cc',
+        'ipc/latency_info_param_traits.h',
+        'ipc/latency_info_param_traits_macros.h',
+      ],
+    },
+  ],
+}
diff --git a/ui/events/latency_info.h b/ui/latency_info/latency_info.h
similarity index 95%
rename from ui/events/latency_info.h
rename to ui/latency_info/latency_info.h
index 22e1ab4..880b4adf 100644
--- a/ui/events/latency_info.h
+++ b/ui/latency_info/latency_info.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef UI_EVENTS_LATENCY_INFO_H_
-#define UI_EVENTS_LATENCY_INFO_H_
+#ifndef UI_LATENCY_INFO_LATENCY_INFO_H_
+#define UI_LATENCY_INFO_LATENCY_INFO_H_
 
 #include <stdint.h>
 
@@ -15,7 +15,7 @@
 #include "base/containers/small_map.h"
 #include "base/time/time.h"
 #include "base/trace_event/trace_event.h"
-#include "ui/events/events_base_export.h"
+#include "ui/latency_info/latency_info_export.h"
 
 #if !defined(OS_IOS)
 #include "ipc/ipc_param_traits.h"  // nogncheck
@@ -97,10 +97,10 @@
   // but the swap failed.
   INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT,
   LATENCY_COMPONENT_TYPE_LAST =
-    INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT,
+      INPUT_EVENT_LATENCY_TERMINATED_SWAP_FAILED_COMPONENT,
 };
 
-class EVENTS_BASE_EXPORT LatencyInfo {
+class LATENCY_INFO_EXPORT LatencyInfo {
  public:
   struct LatencyComponent {
     // Nondecreasing number that can be used to determine what events happened
@@ -113,7 +113,7 @@
     uint32_t event_count;
   };
 
-  struct EVENTS_BASE_EXPORT InputCoordinate {
+  struct LATENCY_INFO_EXPORT InputCoordinate {
     InputCoordinate();
     InputCoordinate(float x, float y);
 
@@ -130,7 +130,8 @@
   // component info.
   typedef base::SmallMap<
       std::map<std::pair<LatencyComponentType, int64_t>, LatencyComponent>,
-      kTypicalMaxComponentsPerLatencyInfo> LatencyMap;
+      kTypicalMaxComponentsPerLatencyInfo>
+      LatencyMap;
 
   LatencyInfo();
   LatencyInfo(const LatencyInfo& other);
@@ -240,4 +241,4 @@
 
 }  // namespace ui
 
-#endif  // UI_EVENTS_LATENCY_INFO_H_
+#endif  // UI_LATENCY_INFO_LATENCY_INFO_H_
diff --git a/ui/latency_info/latency_info_export.h b/ui/latency_info/latency_info_export.h
new file mode 100644
index 0000000..864c966
--- /dev/null
+++ b/ui/latency_info/latency_info_export.h
@@ -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.
+
+#ifndef UI_LATENCY_INFO_LATENCY_INFO_EXPORT_H_
+#define UI_LATENCY_INFO_LATENCY_INFO_EXPORT_H_
+
+#if defined(COMPONENT_BUILD)
+#if defined(WIN32)
+
+#if defined(LATENCY_INFO_IMPLEMENTATION)
+#define LATENCY_INFO_EXPORT __declspec(dllexport)
+#else
+#define LATENCY_INFO_EXPORT __declspec(dllimport)
+#endif  // defined(LATENCY_INFO_IMPLEMENTATION)
+
+#else  // defined(WIN32)
+#if defined(LATENCY_INFO_IMPLEMENTATION)
+#define LATENCY_INFO_EXPORT __attribute__((visibility("default")))
+#else
+#define LATENCY_INFO_EXPORT
+#endif
+#endif
+
+#else  // defined(COMPONENT_BUILD)
+#define LATENCY_INFO_EXPORT
+#endif
+
+#endif  // UI_LATENCY_INFO_LATENCY_INFO_EXPORT_H_
diff --git a/ui/events/latency_info_unittest.cc b/ui/latency_info/latency_info_unittest.cc
similarity index 98%
rename from ui/events/latency_info_unittest.cc
rename to ui/latency_info/latency_info_unittest.cc
index e279863..1d17863a 100644
--- a/ui/events/latency_info_unittest.cc
+++ b/ui/latency_info/latency_info_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ui/events/latency_info.h"
+#include "ui/latency_info/latency_info.h"
 
 #include <stddef.h>
 
diff --git a/ui/latency_info/latency_info_unittests.gyp b/ui/latency_info/latency_info_unittests.gyp
new file mode 100644
index 0000000..d2c9d54
--- /dev/null
+++ b/ui/latency_info/latency_info_unittests.gyp
@@ -0,0 +1,33 @@
+# 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.
+
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      # GN version: //ui/latency_info:latency_info_unittests
+      'target_name': 'latency_info_unittests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        '<(DEPTH)/base/base.gyp:base',
+        '<(DEPTH)/base/base.gyp:run_all_unittests',
+        '<(DEPTH)/base/base.gyp:test_support_base',
+        '<(DEPTH)/ipc/ipc.gyp:test_support_ipc',
+        '<(DEPTH)/testing/gtest.gyp:gtest',
+        'latency_info.gyp:latency_info',
+        'latency_info.gyp:latency_info_ipc',
+      ],
+      'sources': [
+        # Note: sources list duplicated in GN build.
+        'latency_info_unittest.cc',
+        'ipc/latency_info_param_traits_unittest.cc',
+      ],
+      'include_dirs': [
+        '../../testing/gmock/include',
+      ],
+    },
+  ],
+}
diff --git a/ui/views/BUILD.gn b/ui/views/BUILD.gn
index 5b85b89..f88fe268 100644
--- a/ui/views/BUILD.gn
+++ b/ui/views/BUILD.gn
@@ -34,6 +34,7 @@
     "//skia",
     "//third_party/icu",
     "//ui/accessibility",
+    "//ui/latency_info",
     "//ui/native_theme",
     "//ui/resources",
     "//ui/strings",
diff --git a/ui/views/controls/menu/menu_scroll_view_container.cc b/ui/views/controls/menu/menu_scroll_view_container.cc
index f5fd31e..f0d4d4b 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.cc
+++ b/ui/views/controls/menu/menu_scroll_view_container.cc
@@ -8,7 +8,6 @@
 #include "third_party/skia/include/core/SkPaint.h"
 #include "third_party/skia/include/core/SkPath.h"
 #include "ui/accessibility/ax_view_state.h"
-#include "ui/compositor/layer.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/views/border.h"
@@ -35,8 +34,6 @@
 
 class MenuScrollButton : public View {
  public:
-  static const char kViewClassName[];
-
   MenuScrollButton(SubmenuView* host, bool is_up)
       : host_(host),
         is_up_(is_up),
@@ -44,8 +41,6 @@
         pref_height_(MenuItemView::pref_menu_height()) {
   }
 
-  const char* GetClassName() const override { return kViewClassName; }
-
   gfx::Size GetPreferredSize() const override {
     return gfx::Size(MenuConfig::instance().scroll_arrow_height * 2 - 1,
                      pref_height_);
@@ -125,9 +120,6 @@
   DISALLOW_COPY_AND_ASSIGN(MenuScrollButton);
 };
 
-// static
-const char MenuScrollButton::kViewClassName[] = "MenuScrollButton";
-
 }  // namespace
 
 // MenuScrollView --------------------------------------------------------------
@@ -142,18 +134,10 @@
 
 class MenuScrollViewContainer::MenuScrollView : public View {
  public:
-  static const char kViewClassName[];
-
   explicit MenuScrollView(View* child) {
-    SetPaintToLayer(true);
-    layer()->SetMasksToBounds(true);
-    // TODO(bruthig): Paint bounds opaquely.  See http://crbug.com/601135.
-    layer()->SetFillsBoundsOpaquely(false);
     AddChildView(child);
   }
 
-  const char* GetClassName() const override { return kViewClassName; }
-
   void ScrollRectToVisible(const gfx::Rect& rect) override {
     // NOTE: this assumes we only want to scroll in the y direction.
 
@@ -185,16 +169,8 @@
   DISALLOW_COPY_AND_ASSIGN(MenuScrollView);
 };
 
-// static
-const char MenuScrollViewContainer::MenuScrollView::kViewClassName[] =
-    "MenuScrollViewContainer::MenuScrollView";
-
 // MenuScrollViewContainer ----------------------------------------------------
 
-// static
-const char MenuScrollViewContainer::kViewClassName[] =
-    "MenuScrollViewContainer";
-
 MenuScrollViewContainer::MenuScrollViewContainer(SubmenuView* content_view)
     : content_view_(content_view),
       arrow_(BubbleBorder::NONE),
@@ -225,10 +201,6 @@
   bubble_border_->set_arrow_offset(offset);
 }
 
-const char* MenuScrollViewContainer::GetClassName() const {
-  return kViewClassName;
-}
-
 gfx::Size MenuScrollViewContainer::GetPreferredSize() const {
   gfx::Size prefsize = scroll_view_->GetContents()->GetPreferredSize();
   gfx::Insets insets = GetInsets();
diff --git a/ui/views/controls/menu/menu_scroll_view_container.h b/ui/views/controls/menu/menu_scroll_view_container.h
index 469935f..d2a2548c 100644
--- a/ui/views/controls/menu/menu_scroll_view_container.h
+++ b/ui/views/controls/menu/menu_scroll_view_container.h
@@ -19,8 +19,6 @@
 // the preferred height of the SubmenuView is bigger than our bounds.
 class MenuScrollViewContainer : public View {
  public:
-  static const char kViewClassName[];
-
   explicit MenuScrollViewContainer(SubmenuView* content_view);
 
   // Returns the buttons for scrolling up/down.
@@ -34,7 +32,6 @@
   void SetBubbleArrowOffset(int offset);
 
   // View overrides.
-  const char* GetClassName() const override;
   gfx::Size GetPreferredSize() const override;
   void Layout() override;
   void OnPaintBackground(gfx::Canvas* canvas) override;
diff --git a/ui/views/views.gyp b/ui/views/views.gyp
index 43f4ac3..837d206 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -671,6 +671,7 @@
         '../gfx/gfx.gyp:gfx',
         '../gfx/gfx.gyp:gfx_geometry',
         '../gfx/gfx.gyp:gfx_vector_icons',
+        '../latency_info/latency_info.gyp:latency_info',
         '../native_theme/native_theme.gyp:native_theme',
         '../resources/ui_resources.gyp:ui_resources',
         '../strings/ui_strings.gyp:ui_strings',