diff --git a/BUILD.gn b/BUILD.gn
index b42cb10..2d67eaa 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -198,7 +198,6 @@
       "//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 187f2bb..00ac765 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '20efb41dbbbe1f9fa9cd8f3fd8bd84840b79dbbb',
+  'skia_revision': '58700da76b3823de878dde82fee11b80daf7fe18',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -100,7 +100,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '921b5ddf5b7d46c349bc53c0f8694c8b6c3cdb28',
+  'catapult_revision': '321aaf9c5142cdbfef0b249d78d3ffad810bcc21',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
diff --git a/ash/mus/BUILD.gn b/ash/mus/BUILD.gn
index 5f07621df8..bd6a7069 100644
--- a/ash/mus/BUILD.gn
+++ b/ash/mus/BUILD.gn
@@ -39,8 +39,8 @@
     "//mojo/common:common_base",
     "//mojo/converters/geometry",
     "//mojo/converters/input_events",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//skia/public",
     "//ui/app_list/shower",
     "//ui/aura",
diff --git a/ash/mus/DEPS b/ash/mus/DEPS
index da45d5f..e2c9dda 100644
--- a/ash/mus/DEPS
+++ b/ash/mus/DEPS
@@ -9,8 +9,8 @@
   "+mojo/common",
   "+mojo/converters",
   "+mojo/public",
-  "+mojo/services/tracing/public",
   "+services/shell/public",
+  "+services/tracing/public",
   "+skia/public",
   "+third_party/khronos/GLES2/gl2.h",
 ]
diff --git a/ash/mus/sysui_application.h b/ash/mus/sysui_application.h
index a99f1b1b..26e8566 100644
--- a/ash/mus/sysui_application.h
+++ b/ash/mus/sysui_application.h
@@ -10,8 +10,8 @@
 #include "base/macros.h"
 #include "mash/shelf/public/interfaces/shelf.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace ash {
 namespace sysui {
diff --git a/base/message_loop/message_loop_unittest.cc b/base/message_loop/message_loop_unittest.cc
index e0e46e2202..da7cad0 100644
--- a/base/message_loop/message_loop_unittest.cc
+++ b/base/message_loop/message_loop_unittest.cc
@@ -583,6 +583,9 @@
 RUN_MESSAGE_LOOP_TESTS(IO, &TypeIOMessagePumpFactory);
 
 #if defined(OS_WIN)
+// Additional set of tests for GPU version of UI message loop.
+RUN_MESSAGE_LOOP_TESTS(GPU, &MessagePumpForGpu::CreateMessagePumpForGpu);
+
 TEST(MessageLoopTest, PostDelayedTask_SharedTimer_SubPump) {
   RunTest_PostDelayedTask_SharedTimer_SubPump();
 }
diff --git a/base/message_loop/message_pump_win.cc b/base/message_loop/message_pump_win.cc
index 04e76e8b..03e2336e 100644
--- a/base/message_loop/message_pump_win.cc
+++ b/base/message_loop/message_pump_win.cc
@@ -9,6 +9,7 @@
 
 #include <limits>
 
+#include "base/memory/ptr_util.h"
 #include "base/message_loop/message_loop.h"
 #include "base/metrics/histogram.h"
 #include "base/strings/stringprintf.h"
@@ -35,6 +36,9 @@
 // task (a series of such messages creates a continuous task pump).
 static const int kMsgHaveWork = WM_USER + 1;
 
+// The application-defined code passed to the hook procedure.
+static const int kMessageFilterCode = 0x5001;
+
 //-----------------------------------------------------------------------------
 // MessagePumpWin public:
 
@@ -93,7 +97,7 @@
 }
 
 void MessagePumpForUI::ScheduleWork() {
-  if (InterlockedExchange(&have_work_, 1))
+  if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
     return;  // Someone else continued the pumping.
 
   // Make sure the MessagePump does some work for us.
@@ -110,7 +114,9 @@
   // common (queue is full, of about 2000 messages), so we'll do a near-graceful
   // recovery.  Nested loops are pretty transient (we think), so this will
   // probably be recoverable.
-  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't really insert.
+
+  // Clarify that we didn't really insert.
+  InterlockedExchange(&work_state_, READY);
   UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
                             MESSAGE_LOOP_PROBLEM_MAX);
 }
@@ -253,7 +259,7 @@
   // sort.
   if (!state_) {
     // Since we handled a kMsgHaveWork message, we must still update this flag.
-    InterlockedExchange(&have_work_, 0);
+    InterlockedExchange(&work_state_, READY);
     return;
   }
 
@@ -396,8 +402,8 @@
          msg.hwnd != message_hwnd_);
 
   // Since we discarded a kMsgHaveWork message, we must update the flag.
-  int old_have_work = InterlockedExchange(&have_work_, 0);
-  DCHECK(old_have_work);
+  int old_work_state_ = InterlockedExchange(&work_state_, READY);
+  DCHECK_EQ(HAVE_WORK, old_work_state_);
 
   // We don't need a special time slice if we didn't have_message to process.
   if (!have_message)
@@ -412,6 +418,143 @@
 }
 
 //-----------------------------------------------------------------------------
+// MessagePumpForGpu public:
+
+MessagePumpForGpu::MessagePumpForGpu() : thread_id_(GetCurrentThreadId()) {
+  // Init the message queue.
+  MSG msg;
+  PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE);
+}
+
+MessagePumpForGpu::~MessagePumpForGpu() {}
+
+// static
+void MessagePumpForGpu::InitFactory() {
+  bool init_result = MessageLoop::InitMessagePumpForUIFactory(
+      &MessagePumpForGpu::CreateMessagePumpForGpu);
+  DCHECK(init_result);
+}
+
+// static
+std::unique_ptr<MessagePump> MessagePumpForGpu::CreateMessagePumpForGpu() {
+  return WrapUnique<MessagePump>(new MessagePumpForGpu);
+}
+
+void MessagePumpForGpu::ScheduleWork() {
+  if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
+    return;  // Someone else continued the pumping.
+
+  // Make sure the MessagePump does some work for us.
+  BOOL ret = PostThreadMessage(thread_id_, kMsgHaveWork, 0, 0);
+  if (ret)
+    return;  // There was room in the Window Message queue.
+
+  // See comment in MessagePumpForUI::ScheduleWork.
+  InterlockedExchange(&work_state_, READY);
+  UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", MESSAGE_POST_ERROR,
+                            MESSAGE_LOOP_PROBLEM_MAX);
+}
+
+void MessagePumpForGpu::ScheduleDelayedWork(
+    const TimeTicks& delayed_work_time) {
+  // We know that we can't be blocked right now since this method can only be
+  // called on the same thread as Run, so we only need to update our record of
+  // how long to sleep when we do sleep.
+  delayed_work_time_ = delayed_work_time;
+}
+
+//-----------------------------------------------------------------------------
+// MessagePumpForGpu private:
+
+void MessagePumpForGpu::DoRunLoop() {
+  while (!state_->should_quit) {
+    // Indicate that the loop is handling the work.
+    // If there is a race condition between switching to WORKING state here and
+    // the producer thread setting the HAVE_WORK state after exiting the wait,
+    // the event might remain in the signalled state. That might be less than
+    // optimal but wouldn't result in failing to handle the work.
+    InterlockedExchange(&work_state_, WORKING);
+
+    bool more_work_is_plausible = state_->delegate->DoWork();
+    if (state_->should_quit)
+      break;
+
+    more_work_is_plausible |=
+        state_->delegate->DoDelayedWork(&delayed_work_time_);
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    more_work_is_plausible = state_->delegate->DoIdleWork();
+    if (state_->should_quit)
+      break;
+
+    if (more_work_is_plausible)
+      continue;
+
+    // Switch that working state to READY to indicate that the loop is
+    // waiting for accepting new work if it is still in WORKING state and hasn't
+    // been signalled. Otherwise if it is in HAVE_WORK state skip the wait
+    // and proceed to handing the work.
+    if (InterlockedCompareExchange(&work_state_, READY, WORKING) == HAVE_WORK)
+      continue;  // Skip wait, more work was requested.
+
+    WaitForWork();  // Wait (sleep) until we have work to do again.
+  }
+}
+
+void MessagePumpForGpu::WaitForWork() {
+  // Wait until a message is available, up to the time needed by the timer
+  // manager to fire the next set of timers.
+  int delay;
+
+  // The while loop handles the situation where on Windows 7 and later versions
+  // MsgWaitForMultipleObjectsEx might time out slightly earlier (less than one
+  // ms) than the specified |delay|. In that situation it is more optimal to
+  // just wait again rather than waste a DoRunLoop cycle.
+  while ((delay = GetCurrentDelay()) != 0) {
+    if (delay < 0)  // Negative value means no timers waiting.
+      delay = INFINITE;
+
+    DWORD result = MsgWaitForMultipleObjectsEx(0, NULL, delay, QS_ALLINPUT, 0);
+    if (result == WAIT_OBJECT_0) {
+      // A WM_* message is available.
+      if (ProcessMessages())
+        return;
+    }
+
+    DCHECK_NE(WAIT_FAILED, result) << GetLastError();
+  }
+}
+
+bool MessagePumpForGpu::ProcessMessages() {
+  MSG msg;
+  bool have_work = false;
+  while (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
+    if (msg.message == WM_QUIT) {
+      // Repost the QUIT message so that it will be retrieved by the primary
+      // GetMessage() loop.
+      state_->should_quit = true;
+      PostQuitMessage(static_cast<int>(msg.wParam));
+      return true;
+    }
+
+    if (msg.hwnd == nullptr && msg.message == kMsgHaveWork) {
+      have_work = true;
+    } else {
+      if (!CallMsgFilter(const_cast<MSG*>(&msg), kMessageFilterCode)) {
+        TranslateMessage(&msg);
+        DispatchMessage(&msg);
+      }
+    }
+  }
+
+  return have_work;
+}
+
+//-----------------------------------------------------------------------------
 // MessagePumpForIO public:
 
 MessagePumpForIO::MessagePumpForIO() {
@@ -423,7 +566,7 @@
 }
 
 void MessagePumpForIO::ScheduleWork() {
-  if (InterlockedExchange(&have_work_, 1))
+  if (InterlockedExchange(&work_state_, HAVE_WORK) != READY)
     return;  // Someone else continued the pumping.
 
   // Make sure the MessagePump does some work for us.
@@ -434,7 +577,7 @@
     return;  // Post worked perfectly.
 
   // See comment in MessagePumpForUI::ScheduleWork() for this error recovery.
-  InterlockedExchange(&have_work_, 0);  // Clarify that we didn't succeed.
+  InterlockedExchange(&work_state_, READY);  // Clarify that we didn't succeed.
   UMA_HISTOGRAM_ENUMERATION("Chrome.MessageLoopProblem", COMPLETION_POST_ERROR,
                             MESSAGE_LOOP_PROBLEM_MAX);
 }
@@ -579,7 +722,7 @@
       reinterpret_cast<void*>(this) == reinterpret_cast<void*>(item.handler)) {
     // This is our internal completion.
     DCHECK(!item.bytes_transfered);
-    InterlockedExchange(&have_work_, 0);
+    InterlockedExchange(&work_state_, READY);
     return true;
   }
   return false;
diff --git a/base/message_loop/message_pump_win.h b/base/message_loop/message_pump_win.h
index 6f4b699..ac9f68a 100644
--- a/base/message_loop/message_pump_win.h
+++ b/base/message_loop/message_pump_win.h
@@ -8,6 +8,7 @@
 #include <windows.h>
 
 #include <list>
+#include <memory>
 
 #include "base/base_export.h"
 #include "base/message_loop/message_pump.h"
@@ -22,7 +23,7 @@
 // controlling the lifetime of the message pump.
 class BASE_EXPORT MessagePumpWin : public MessagePump {
  public:
-  MessagePumpWin() : have_work_(0), state_(NULL) {}
+  MessagePumpWin() : work_state_(READY), state_(NULL) {}
 
   // MessagePump methods:
   void Run(Delegate* delegate) override;
@@ -39,16 +40,23 @@
     int run_depth;
   };
 
+  // State used with |work_state_| variable.
+  enum WorkState {
+    READY = 0,      // Ready to accept new work.
+    HAVE_WORK = 1,  // New work has been signalled.
+    WORKING = 2     // Handling the work.
+  };
+
   virtual void DoRunLoop() = 0;
   int GetCurrentDelay() const;
 
   // The time at which delayed work should run.
   TimeTicks delayed_work_time_;
 
-  // A boolean value used to indicate if there is a kMsgDoWork message pending
+  // A value used to indicate if there is a kMsgDoWork message pending
   // in the Windows Message queue.  There is at most one such message, and it
   // can drive execution of tasks when a native message pump is running.
-  LONG have_work_;
+  LONG work_state_;
 
   // State for the current invocation of Run.
   RunState* state_;
@@ -104,9 +112,6 @@
 //
 class BASE_EXPORT MessagePumpForUI : public MessagePumpWin {
  public:
-  // The application-defined code passed to the hook procedure.
-  static const int kMessageFilterCode = 0x5001;
-
   MessagePumpForUI();
   ~MessagePumpForUI() override;
 
@@ -137,6 +142,35 @@
 };
 
 //-----------------------------------------------------------------------------
+// MessagePumpForGpu is a simplified version of UI message pump that is
+// optimized for the GPU process. Unlike MessagePumpForUI it doesn't have a
+// hidden window and doesn't handle a situation where a native message pump
+// might take over message processing.
+//
+class BASE_EXPORT MessagePumpForGpu : public MessagePumpWin {
+ public:
+  MessagePumpForGpu();
+  ~MessagePumpForGpu() override;
+
+  // Factory methods.
+  static void InitFactory();
+  static std::unique_ptr<MessagePump> CreateMessagePumpForGpu();
+
+  // MessagePump methods:
+  void ScheduleWork() override;
+  void ScheduleDelayedWork(const TimeTicks& delayed_work_time) override;
+
+ private:
+  // MessagePumpWin methods:
+  void DoRunLoop() override;
+
+  void WaitForWork();
+  bool ProcessMessages();
+
+  const DWORD thread_id_;
+};
+
+//-----------------------------------------------------------------------------
 // MessagePumpForIO extends MessagePumpWin with methods that are particular to a
 // MessageLoop instantiated with TYPE_IO. This version of MessagePump does not
 // deal with Windows mesagges, and instead has a Run loop based on Completion
diff --git a/build/all.gyp b/build/all.gyp
index 83bbf64..1635f82 100644
--- a/build/all.gyp
+++ b/build/all.gyp
@@ -141,6 +141,7 @@
             '../ppapi/ppapi.gyp:*',
             '../ppapi/ppapi_internal.gyp:*',
             '../ppapi/tools/ppapi_tools.gyp:*',
+            '../services/shell/shell.gyp:*',
             '../skia/skia.gyp:*',
             '../sync/tools/sync_tools.gyp:*',
             '../third_party/catapult/telemetry/telemetry.gyp:*',
@@ -826,7 +827,6 @@
             '../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,7 +855,6 @@
             '../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': [
@@ -1055,7 +1054,6 @@
             '../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',
@@ -1159,7 +1157,6 @@
             '../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',
           ],
@@ -1278,7 +1275,6 @@
             '../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/args/blimp_engine.gn b/build/args/blimp_engine.gn
index a5f20e3..2500b30b 100644
--- a/build/args/blimp_engine.gn
+++ b/build/args/blimp_engine.gn
@@ -6,9 +6,6 @@
 # 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/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 8682ae5..ce48fed 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -255,7 +255,7 @@
     ubsan_blacklist_path =
         rebase_path("//tools/ubsan/blacklist.txt", root_build_dir)
     cflags += [
-      "-fsanitize=signed-integer-overflow",
+      "-fsanitize=signed-integer-overflow,shift",
       "-fsanitize-blacklist=$ubsan_blacklist_path",
     ]
   }
diff --git a/build/gn_migration.gypi b/build/gn_migration.gypi
index bca3cf7d..26ec59a 100644
--- a/build/gn_migration.gypi
+++ b/build/gn_migration.gypi
@@ -71,7 +71,6 @@
         '../media/media.gyp:media_perftests',
         '../media/media.gyp:media_unittests',
         '../media/midi/midi.gyp:midi_unittests',
-        '../mojo/mojo_base.gyp:mojo_application_base',
         '../net/net.gyp:dump_cache',
         '../net/net.gyp:net_perftests',
         '../net/net.gyp:net_unittests',
diff --git a/build/secondary/third_party/libjpeg_turbo/BUILD.gn b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
index 09e5eb49..847c94a9 100644
--- a/build/secondary/third_party/libjpeg_turbo/BUILD.gn
+++ b/build/secondary/third_party/libjpeg_turbo/BUILD.gn
@@ -82,7 +82,7 @@
       } else {
         defines += [ "WIN64" ]
       }
-    } else if (is_mac) {
+    } else if (is_mac || is_ios) {
       defines += [ "MACHO" ]
       include_dirs = [ "mac" ]
     } else if (is_linux || is_android) {
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index 984b76f..f1f05f5 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 93452863..f1bdb3f 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/latency_info",
+  "+ui/events/latency_info.h",
   "+ui/gfx",
   "+ui/gl",
   "-cc/blink",
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 4e6a0d88..69ab8395 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 b2aec9f..fb5d987 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/output/compositor_frame_metadata.h b/cc/output/compositor_frame_metadata.h
index c73499d..54b2047 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 4b59159..23a1c862 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 namespace cc {
 
diff --git a/cc/surfaces/BUILD.gn b/cc/surfaces/BUILD.gn
index c64d96e5..1c5ca5c 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 3ab9cefb..cb8e898b 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 namespace gpu {
 class GpuMemoryBufferManager;
diff --git a/chrome/VERSION b/chrome/VERSION
index a4abf00..76c15db 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=52
 MINOR=0
-BUILD=2707
+BUILD=2708
 PATCH=0
diff --git a/chrome/android/java/res/layout/text_message_with_link_and_icon_preference.xml b/chrome/android/java/res/layout/text_message_with_link_and_icon_preference.xml
index cb7a765..c5d4f9f 100644
--- a/chrome/android/java/res/layout/text_message_with_link_and_icon_preference.xml
+++ b/chrome/android/java/res/layout/text_message_with_link_and_icon_preference.xml
@@ -9,7 +9,8 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     style="@style/PreferenceLayout"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content">
+    android:layout_height="wrap_content"
+    android:paddingBottom="24dp">
 
     <ImageView
         android:id="@+android:id/icon"
diff --git a/chrome/android/java/res/values/attrs.xml b/chrome/android/java/res/values/attrs.xml
index acb3e8b..1bdd359 100644
--- a/chrome/android/java/res/values/attrs.xml
+++ b/chrome/android/java/res/values/attrs.xml
@@ -60,4 +60,12 @@
     <declare-styleable name="RadioButtonWithDescription">
         <attr name="titleText" format="string" />
     </declare-styleable>
+
+    <declare-styleable name="TextMessageWithLinkAndIconPreference">
+        <!-- Used on a TextMessageWithLinkAndIconPreference that is followed
+             by another TextMessageWithLinkAndIconPreference to remove the
+             bottom spacing, so that related paragraphs of text are closer
+             to each other. -->
+        <attr name="noBottomSpacing" format="boolean" />
+    </declare-styleable>
 </resources>
diff --git a/chrome/android/java/res/xml/clear_browsing_data_preferences.xml b/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
index c4a7dd82..6e9c43db 100644
--- a/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
+++ b/chrome/android/java/res/xml/clear_browsing_data_preferences.xml
@@ -47,7 +47,8 @@
     <org.chromium.chrome.browser.preferences.TextMessageWithLinkAndIconPreference
         android:key="google_summary"
         android:summary="@string/clear_browsing_data_footnote_signed"
-        android:icon="@drawable/googleg" />
+        android:icon="@drawable/googleg"
+        chrome:noBottomSpacing="true" />
 
     <org.chromium.chrome.browser.preferences.TextMessageWithLinkAndIconPreference
         android:key="general_summary"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessageWithLinkAndIconPreference.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessageWithLinkAndIconPreference.java
index b2c0805e..17742405 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessageWithLinkAndIconPreference.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/TextMessageWithLinkAndIconPreference.java
@@ -5,13 +5,17 @@
 package org.chromium.chrome.browser.preferences;
 
 import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint.FontMetrics;
 import android.text.SpannableString;
 import android.text.method.LinkMovementMethod;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ImageView;
 import android.widget.TextView;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.ui.text.NoUnderlineClickableSpan;
 import org.chromium.ui.text.SpanApplier;
@@ -22,6 +26,7 @@
  */
 public class TextMessageWithLinkAndIconPreference extends TextMessagePreference {
     private Runnable mLinkClickDelegate;
+    private boolean mNoBottomSpacing;
 
     /**
      * Constructor for inflating from XML.
@@ -29,6 +34,12 @@
     public TextMessageWithLinkAndIconPreference(Context context, AttributeSet attrs) {
         super(context, attrs);
         setLayoutResource(R.layout.text_message_with_link_and_icon_preference);
+
+        TypedArray a = context.obtainStyledAttributes(
+                attrs, R.styleable.TextMessageWithLinkAndIconPreference);
+        mNoBottomSpacing = a.getBoolean(
+                R.styleable.TextMessageWithLinkAndIconPreference_noBottomSpacing, false);
+        a.recycle();
     }
 
     /**
@@ -62,8 +73,28 @@
     @Override
     public View onCreateView(ViewGroup parent) {
         View view = super.onCreateView(parent);
+
+        if (mNoBottomSpacing) {
+            ApiCompatibilityUtils.setPaddingRelative(
+                    view,
+                    ApiCompatibilityUtils.getPaddingStart(view),
+                    view.getPaddingTop(),
+                    ApiCompatibilityUtils.getPaddingEnd(view),
+                    0);
+        }
+
         ((TextView) view.findViewById(android.R.id.summary)).setMovementMethod(
                 LinkMovementMethod.getInstance());
+
+        // The icon is aligned to the top of the text view, which can be higher than the
+        // ascender line of the text, and makes it look aligned improperly.
+        TextView textView = (TextView) view.findViewById(
+                getTitle() != null ? android.R.id.title : android.R.id.summary);
+        FontMetrics metrics = textView.getPaint().getFontMetrics();
+        ImageView icon = (ImageView) view.findViewById(android.R.id.icon);
+        ApiCompatibilityUtils.setPaddingRelative(
+                icon, 0, (int) java.lang.Math.ceil(metrics.ascent - metrics.top), 0, 0);
+
         return view;
     }
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index fabf9235..009916c2 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6281,6 +6281,12 @@
         <message name="IDS_FLAGS_HOSTED_APPS_IN_WINDOWS_DESCRIPTION" desc="Description for the flag to allow hosted apps opening in windows">
           Allows hosted apps to be opened in windows instead of being limited to tabs.
         </message>
+        <message name="IDS_FLAGS_TAB_DETACHING_IN_FULLSCREEN_NAME" desc="Name of the flag to allow tabs detaching in fullscreen on Mac.">
+          Allow tab detaching in fullscreen
+        </message>
+        <message name="IDS_FLAGS_TAB_DETACHING_IN_FULLSCREEN_DESCRIPTION" desc="Description for the flag to allow tabs detaching in fullscreen on Mac">
+          Allow tabs to detach from the tabstrip when in fullscreen mode on Mac.
+        </message>
       </if>
       <message name="IDS_FLAGS_HOSTED_APP_SHIM_CREATION_NAME" desc="Name of the flag to enable creation of app shims for hosted apps on Mac.">
         Creation of app shims for hosted apps on Mac
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index b5edeeae..e1c077ad9 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -578,20 +578,26 @@
   </message>
 
   <!-- Languages Page -->
-  <message name="IDS_SETTINGS_LANGUAGES_PAGE_TITLE" desc="Name of the settings page which displays language and input method preferences.">
+  <message name="IDS_SETTINGS_LANGUAGES_PAGE_TITLE" desc="Name of the settings page which displays language preferences.">
     Languages
   </message>
-  <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_TITLE" desc="Title for the list of languages that are enabled.">
-    Languages
+  <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_LIST_TITLE" desc="Title for the currently used language in the header for the collapsible list of languages.">
+    Language
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_LANGUAGES_MANAGE" desc="Button under the list of enabled languages which opens a sub-page that lets the user enable or disable languages.">
     Manage languages
   </message>
-  <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE" desc="Title for the list of input methods (keyboard layouts and input method editors) that are enabled.">
-    Input methods
+  <message name="IDS_SETTINGS_LANGUAGES_OFFER_TO_TRANSLATE_IN_THIS_LANGUAGE" desc="The label for a checkbox which indicates whether or not pages in this language should be translated by default.">
+    Offer to translate pages in this language
   </message>
-  <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGE" desc="Button under the list of input methods which opens a sub-page that lets the user enable or disable devices (such as keyboards).">
-    Manage devices
+  <message name="IDS_SETTINGS_LANGUAGES_CANNOT_TRANSLATE_IN_THIS_LANGUAGE" desc="The string displayed in the details for a language when the language cannot be translated from.">
+    This language cannot be translated
+  </message>
+  <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_LIST_TITLE" desc="Title for the current input method in the header for the collapsible list of enabled input methods (keyboard layouts and input method editors).">
+    Input method
+  </message>
+  <message name="IDS_SETTINGS_LANGUAGES_INPUT_METHODS_MANAGE" desc="Button under the list of input methods which opens a sub-page that lets the user enable or disable keyboard layouts and input method editors.">
+    Manage inputs
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_SPELL_CHECK_LIST_TITLE" desc="Title for the section containing the dropdown used to select the language to use for spell checking. The dropdown contains the enabled languages which support spell checking.">
     Spell check
@@ -600,7 +606,7 @@
     Custom spelling
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_MANAGE_LANGUAGES_TITLE" desc="Name of the settings sub-page which allows enabling and disabling languages.">
-    Languages
+    Manage languages
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_ALL_LANGUAGES" desc="Header for the list of all supported languages, which the user can use to enable languages, on the Manage Languages page.">
     All languages
@@ -609,7 +615,7 @@
     Enabled languages
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_TITLE" desc="Name of the settings sub-page which allows adding and remove custom words from the custom spell check dictionary.">
-    Custom spelling dictionary
+    Manage spell check
   </message>
   <message name="IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD" desc="Label for the text input used to add a new word to the custom spell check dictionary.">
     Add a new word
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 5633a90..d22da25 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -1313,6 +1313,7 @@
 
   deps = [
     "//components/metrics:test_support",
+    "//components/password_manager/content/public/interfaces",
     "//components/password_manager/core/browser:test_support",
     "//skia",
     "//testing/gtest",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 6a6b387..688b570 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -1816,6 +1816,12 @@
      IDS_FLAGS_GOOGLE_BRANDED_CONTEXT_MENU_DESCRIPTION, kOsDesktop,
      SINGLE_VALUE_TYPE(switches::kEnableGoogleBrandedContextMenu)},
 #endif
+#if defined(OS_MACOSX)
+    {"enable-fullscreen-in-tab-detaching",
+     IDS_FLAGS_TAB_DETACHING_IN_FULLSCREEN_NAME,
+     IDS_FLAGS_TAB_DETACHING_IN_FULLSCREEN_DESCRIPTION, kOsMac,
+     SINGLE_VALUE_TYPE(switches::kEnableFullscreenTabDetaching)},
+#endif
     // NOTE: Adding new command-line switches requires adding corresponding
     // entries to enum "LoginCustomFlags" in histograms.xml. See note in
     // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test.
diff --git a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
index 5c57631..99f00264 100644
--- a/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
+++ b/chrome/browser/apps/guest_view/web_view_interactive_browsertest.cc
@@ -1379,8 +1379,16 @@
   EXPECT_TRUE(webview_button_not_focused_listener.WaitUntilSatisfied());
 }
 
+// TODO(crbug.com/602954) Test is flaky.
+#if defined(OS_WIN)
+#define MAYBE_TopLevelWebContentsTracksCorrectly \
+  DISABLED_TopLevelWebContentsTracksCorrectly
+#else
+#define MAYBE_TopLevelWebContentsTracksCorrectly \
+  TopLevelWebContentsTracksCorrectly
+#endif
 IN_PROC_BROWSER_TEST_P(WebViewTextInputStateInteractiveTest,
-                       TopLevelWebContentsTracksCorrectly) {
+                       MAYBE_TopLevelWebContentsTracksCorrectly) {
   SetupTest("web_view/text_input_state",
             "/extensions/platform_apps/web_view/text_input_state/guest.html");
 
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 8f5d195d..d0a8804 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -53,6 +53,7 @@
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings.h"
 #include "chrome/browser/net/spdyproxy/data_reduction_proxy_chrome_settings_factory.h"
 #include "chrome/browser/notifications/platform_notification_service_impl.h"
+#include "chrome/browser/password_manager/chrome_password_manager_client.h"
 #include "chrome/browser/permissions/permission_context_base.h"
 #include "chrome/browser/platform_util.h"
 #include "chrome/browser/prerender/prerender_final_status.h"
@@ -2768,6 +2769,13 @@
         base::Bind(&CreateWebUsbChooserService, render_frame_host));
   }
 
+  // Register mojo CredentialManager service only for main frame.
+  if (!render_frame_host->GetParent()) {
+    registry->AddService(
+        base::Bind(&ChromePasswordManagerClient::BindCredentialManager,
+                   render_frame_host));
+  }
+
 #if BUILDFLAG(ANDROID_JAVA_UI)
   ChromeServiceRegistrarAndroid::RegisterRenderFrameMojoServices(registry);
 #endif
diff --git a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
index 3f53b67..c02db2e8 100644
--- a/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
+++ b/chrome/browser/chromeos/login/login_ui_keyboard_browsertest.cc
@@ -144,7 +144,8 @@
   StartupUtils::MarkOobeCompleted();
 }
 
-IN_PROC_BROWSER_TEST_F(LoginUIKeyboardTest, CheckPODScreenWithUsers) {
+// TODO(crbug.com/602951): Test is flaky.
+IN_PROC_BROWSER_TEST_F(LoginUIKeyboardTest, DISABLED_CheckPODScreenWithUsers) {
   js_checker().ExpectEQ("$('pod-row').pods.length", 2);
 
   EXPECT_EQ(user_input_methods[0],
diff --git a/chrome/browser/devtools/chrome_devtools_discovery_provider.cc b/chrome/browser/devtools/chrome_devtools_discovery_provider.cc
index 761c2b4..7343c77 100644
--- a/chrome/browser/devtools/chrome_devtools_discovery_provider.cc
+++ b/chrome/browser/devtools/chrome_devtools_discovery_provider.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/devtools/chrome_devtools_discovery_provider.h"
 
+#include "base/memory/ptr_util.h"
 #include "chrome/browser/devtools/devtools_target_impl.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/ui/browser_navigator.h"
@@ -11,14 +12,14 @@
 
 namespace {
 
-scoped_ptr<devtools_discovery::DevToolsTargetDescriptor>
+std::unique_ptr<devtools_discovery::DevToolsTargetDescriptor>
 CreateNewChromeTab(const GURL& url) {
   chrome::NavigateParams params(ProfileManager::GetLastUsedProfile(),
       url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL);
   params.disposition = NEW_FOREGROUND_TAB;
   chrome::Navigate(&params);
   if (!params.target_contents)
-    return scoped_ptr<devtools_discovery::DevToolsTargetDescriptor>();
+    return std::unique_ptr<devtools_discovery::DevToolsTargetDescriptor>();
   return DevToolsTargetImpl::CreateForTab(params.target_contents);
 }
 
@@ -45,6 +46,6 @@
   devtools_discovery::DevToolsDiscoveryManager* discovery_manager =
       devtools_discovery::DevToolsDiscoveryManager::GetInstance();
   discovery_manager->AddProvider(
-      make_scoped_ptr(new ChromeDevToolsDiscoveryProvider()));
+      base::WrapUnique(new ChromeDevToolsDiscoveryProvider()));
   discovery_manager->SetCreateCallback(base::Bind(&CreateNewChromeTab));
 }
diff --git a/chrome/browser/devtools/chrome_devtools_manager_delegate.h b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
index 99b6cc2..318dc05 100644
--- a/chrome/browser/devtools/chrome_devtools_manager_delegate.h
+++ b/chrome/browser/devtools/chrome_devtools_manager_delegate.h
@@ -5,9 +5,10 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_CHROME_DEVTOOLS_MANAGER_DELEGATE_H_
 #define CHROME_BROWSER_DEVTOOLS_CHROME_DEVTOOLS_MANAGER_DELEGATE_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "content/public/browser/devtools_manager_delegate.h"
 
 class DevToolsNetworkProtocolHandler;
@@ -27,7 +28,7 @@
       base::DictionaryValue* command_dict) override;
 
  private:
-  scoped_ptr<DevToolsNetworkProtocolHandler> network_protocol_handler_;
+  std::unique_ptr<DevToolsNetworkProtocolHandler> network_protocol_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(ChromeDevToolsManagerDelegate);
 };
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket.cc b/chrome/browser/devtools/device/adb/adb_client_socket.cc
index 9552ef0..81eaaac 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket.cc
+++ b/chrome/browser/devtools/device/adb/adb_client_socket.cc
@@ -5,10 +5,12 @@
 #include "chrome/browser/devtools/device/adb/adb_client_socket.h"
 
 #include <stddef.h>
+
 #include <utility>
 
 #include "base/bind.h"
 #include "base/compiler_specific.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
@@ -81,7 +83,7 @@
   bool CheckNetResultOrDie(int result) {
     if (result >= 0)
       return true;
-    callback_.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+    callback_.Run(result, base::WrapUnique<net::StreamSocket>(NULL));
     delete this;
     return false;
   }
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket.h b/chrome/browser/devtools/device/adb/adb_client_socket.h
index acdfec9..bff3bad0 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket.h
+++ b/chrome/browser/devtools/device/adb/adb_client_socket.h
@@ -13,8 +13,8 @@
 class AdbClientSocket {
  public:
   typedef base::Callback<void(int, const std::string&)> CommandCallback;
-  typedef base::Callback<void(int result,
-                              scoped_ptr<net::StreamSocket>)> SocketCallback;
+  typedef base::Callback<void(int result, std::unique_ptr<net::StreamSocket>)>
+      SocketCallback;
 
   static void AdbQuery(int port,
                        const std::string& query,
@@ -36,7 +36,7 @@
                    bool is_void,
                    const CommandCallback& callback);
 
-  scoped_ptr<net::StreamSocket> socket_;
+  std::unique_ptr<net::StreamSocket> socket_;
 
  private:
   void ReadResponse(const CommandCallback& callback, bool is_void, int result);
diff --git a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
index e770085..341c1b6 100644
--- a/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
+++ b/chrome/browser/devtools/device/adb/adb_client_socket_browsertest.cc
@@ -108,13 +108,13 @@
     ASSERT_EQ(1U, chrome_beta_pages.size());
     ASSERT_EQ(2U, webview_pages.size());
 
-    scoped_ptr<DevToolsTargetImpl> chrome_target(
+    std::unique_ptr<DevToolsTargetImpl> chrome_target(
         android_bridge_->CreatePageTarget(chrome_pages[0]));
-    scoped_ptr<DevToolsTargetImpl> chrome_beta_target(
+    std::unique_ptr<DevToolsTargetImpl> chrome_beta_target(
         android_bridge_->CreatePageTarget(chrome_beta_pages[0]));
-    scoped_ptr<DevToolsTargetImpl> webview_target_0(
+    std::unique_ptr<DevToolsTargetImpl> webview_target_0(
         android_bridge_->CreatePageTarget(webview_pages[0]));
-    scoped_ptr<DevToolsTargetImpl> webview_target_1(
+    std::unique_ptr<DevToolsTargetImpl> webview_target_1(
         android_bridge_->CreatePageTarget(webview_pages[1]));
 
     // Check that we have non-empty description for webview pages.
diff --git a/chrome/browser/devtools/device/adb/mock_adb_server.cc b/chrome/browser/devtools/device/adb/mock_adb_server.cc
index bd0e0fe..0920319 100644
--- a/chrome/browser/devtools/device/adb/mock_adb_server.cc
+++ b/chrome/browser/devtools/device/adb/mock_adb_server.cc
@@ -9,6 +9,7 @@
 
 #include "base/location.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/memory/weak_ptr.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
@@ -207,8 +208,8 @@
     void WriteData();
     void OnDataWritten(int count);
 
-    scoped_ptr<net::StreamSocket> socket_;
-    scoped_ptr<Parser> parser_;
+    std::unique_ptr<net::StreamSocket> socket_;
+    std::unique_ptr<Parser> parser_;
     scoped_refptr<net::GrowableIOBuffer> input_buffer_;
     scoped_refptr<net::GrowableIOBuffer> output_buffer_;
     int bytes_to_write_;
@@ -222,8 +223,8 @@
   void OnAccepted(int result);
 
   ParserFactory factory_;
-  scoped_ptr<net::TCPServerSocket> socket_;
-  scoped_ptr<net::StreamSocket> client_socket_;
+  std::unique_ptr<net::TCPServerSocket> socket_;
+  std::unique_ptr<net::StreamSocket> client_socket_;
   base::WeakPtrFactory<SimpleHttpServer> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(SimpleHttpServer);
@@ -432,8 +433,8 @@
     } else if (serial_ != kSerialOnline) {
       Send("FAIL", "device offline (x)");
     } else {
-      mock_connection_ = make_scoped_ptr(
-          new MockAndroidConnection(this, serial_, command));
+      mock_connection_ =
+          base::WrapUnique(new MockAndroidConnection(this, serial_, command));
     }
   }
 
@@ -473,7 +474,7 @@
   FlushMode flush_mode_;
   SimpleHttpServer::SendCallback callback_;
   std::string serial_;
-  scoped_ptr<MockAndroidConnection> mock_connection_;
+  std::unique_ptr<MockAndroidConnection> mock_connection_;
 };
 
 static SimpleHttpServer* mock_adb_server_ = NULL;
diff --git a/chrome/browser/devtools/device/android_device_manager.cc b/chrome/browser/devtools/device/android_device_manager.cc
index ccae719..a387623 100644
--- a/chrome/browser/devtools/device/android_device_manager.cc
+++ b/chrome/browser/devtools/device/android_device_manager.cc
@@ -6,9 +6,11 @@
 
 #include <stddef.h>
 #include <string.h>
+
 #include <utility>
 
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
@@ -59,7 +61,7 @@
     int result,
     const std::string& extensions,
     const std::string& body_head,
-    scoped_ptr<net::StreamSocket> socket) {
+    std::unique_ptr<net::StreamSocket> socket) {
   response_task_runner->PostTask(
       FROM_HERE, base::Bind(callback, result, extensions, body_head,
                             base::Passed(&socket)));
@@ -73,7 +75,7 @@
   static void CommandRequest(const std::string& request,
                              const CommandCallback& callback,
                              int result,
-                             scoped_ptr<net::StreamSocket> socket) {
+                             std::unique_ptr<net::StreamSocket> socket) {
     if (result != net::OK) {
       callback.Run(result, std::string());
       return;
@@ -84,18 +86,17 @@
   static void HttpUpgradeRequest(const std::string& request,
                                  const HttpUpgradeCallback& callback,
                                  int result,
-                                 scoped_ptr<net::StreamSocket> socket) {
+                                 std::unique_ptr<net::StreamSocket> socket) {
     if (result != net::OK) {
-      callback.Run(
-          result, std::string(), std::string(),
-          make_scoped_ptr<net::StreamSocket>(nullptr));
+      callback.Run(result, std::string(), std::string(),
+                   base::WrapUnique<net::StreamSocket>(nullptr));
       return;
     }
     new HttpRequest(std::move(socket), request, callback);
   }
 
  private:
-  HttpRequest(scoped_ptr<net::StreamSocket> socket,
+  HttpRequest(std::unique_ptr<net::StreamSocket> socket,
               const std::string& request,
               const CommandCallback& callback)
       : socket_(std::move(socket)),
@@ -105,7 +106,7 @@
     SendRequest(request);
   }
 
-  HttpRequest(scoped_ptr<net::StreamSocket> socket,
+  HttpRequest(std::unique_ptr<net::StreamSocket> socket,
               const std::string& request,
               const HttpUpgradeCallback& callback)
       : socket_(std::move(socket)),
@@ -236,15 +237,14 @@
     if (!command_callback_.is_null()) {
       command_callback_.Run(result, std::string());
     } else {
-      http_upgrade_callback_.Run(
-          result, std::string(), std::string(),
-          make_scoped_ptr<net::StreamSocket>(nullptr));
+      http_upgrade_callback_.Run(result, std::string(), std::string(),
+                                 base::WrapUnique<net::StreamSocket>(nullptr));
     }
     delete this;
     return false;
   }
 
-  scoped_ptr<net::StreamSocket> socket_;
+  std::unique_ptr<net::StreamSocket> socket_;
   scoped_refptr<net::DrainableIOBuffer> request_;
   std::string response_;
   CommandCallback command_callback_;
@@ -268,7 +268,7 @@
   typedef AndroidDeviceManager::DeviceProvider DeviceProvider;
   typedef AndroidDeviceManager::DeviceProviders DeviceProviders;
   typedef AndroidDeviceManager::DeviceDescriptors DeviceDescriptors;
-  typedef base::Callback<void(scoped_ptr<DeviceDescriptors>)>
+  typedef base::Callback<void(std::unique_ptr<DeviceDescriptors>)>
       DescriptorsCallback;
 
   static void Start(
@@ -315,7 +315,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> response_task_runner_;
   DescriptorsCallback callback_;
-  scoped_ptr<DeviceDescriptors> descriptors_;
+  std::unique_ptr<DeviceDescriptors> descriptors_;
 };
 
 void ReleaseDeviceAndProvider(
@@ -503,8 +503,8 @@
 }
 
 // static
-scoped_ptr<AndroidDeviceManager> AndroidDeviceManager::Create() {
-  return make_scoped_ptr(new AndroidDeviceManager());
+std::unique_ptr<AndroidDeviceManager> AndroidDeviceManager::Create() {
+  return base::WrapUnique(new AndroidDeviceManager());
 }
 
 void AndroidDeviceManager::SetDeviceProviders(
@@ -536,7 +536,7 @@
 
 void AndroidDeviceManager::UpdateDevices(
     const DevicesCallback& callback,
-    scoped_ptr<DeviceDescriptors> descriptors) {
+    std::unique_ptr<DeviceDescriptors> descriptors) {
   Devices response;
   DeviceWeakMap new_devices;
   for (DeviceDescriptors::const_iterator it = descriptors->begin();
diff --git a/chrome/browser/devtools/device/android_device_manager.h b/chrome/browser/devtools/device/android_device_manager.h
index 55dac0e..a487d47 100644
--- a/chrome/browser/devtools/device/android_device_manager.h
+++ b/chrome/browser/devtools/device/android_device_manager.h
@@ -25,14 +25,14 @@
   using CommandCallback =
       base::Callback<void(int, const std::string&)>;
   using SocketCallback =
-      base::Callback<void(int result, scoped_ptr<net::StreamSocket>)>;
+      base::Callback<void(int result, std::unique_ptr<net::StreamSocket>)>;
   // |body_head| should contain the body (WebSocket frame data) part that has
   // been read during processing the header (WebSocket handshake).
-  using HttpUpgradeCallback = base::Callback<void(
-      int result,
-      const std::string& extensions,
-      const std::string& body_head,
-      scoped_ptr<net::StreamSocket>)>;
+  using HttpUpgradeCallback =
+      base::Callback<void(int result,
+                          const std::string& extensions,
+                          const std::string& body_head,
+                          std::unique_ptr<net::StreamSocket>)>;
   using SerialsCallback =
       base::Callback<void(const std::vector<std::string>&)>;
 
@@ -94,7 +94,7 @@
     void Connected(int result,
                    const std::string& extensions,
                    const std::string& body_head,
-                   scoped_ptr<net::StreamSocket> socket);
+                   std::unique_ptr<net::StreamSocket> socket);
     void OnFrameRead(const std::string& message);
     void OnSocketClosed();
     void Terminate();
@@ -193,7 +193,7 @@
 
   virtual ~AndroidDeviceManager();
 
-  static scoped_ptr<AndroidDeviceManager> Create();
+  static std::unique_ptr<AndroidDeviceManager> Create();
 
   void SetDeviceProviders(const DeviceProviders& providers);
 
@@ -237,7 +237,7 @@
   AndroidDeviceManager();
 
   void UpdateDevices(const DevicesCallback& callback,
-                     scoped_ptr<DeviceDescriptors> descriptors);
+                     std::unique_ptr<DeviceDescriptors> descriptors);
 
   typedef std::map<std::string, base::WeakPtr<Device> > DeviceWeakMap;
 
diff --git a/chrome/browser/devtools/device/android_web_socket.cc b/chrome/browser/devtools/device/android_web_socket.cc
index e8af926..55f1c11 100644
--- a/chrome/browser/devtools/device/android_web_socket.cc
+++ b/chrome/browser/devtools/device/android_web_socket.cc
@@ -33,7 +33,7 @@
       base::WeakPtr<AndroidWebSocket> weak_socket,
       const std::string& extensions,
       const std::string& body_head,
-      scoped_ptr<net::StreamSocket> socket)
+      std::unique_ptr<net::StreamSocket> socket)
       : response_task_runner_(response_task_runner),
         weak_socket_(weak_socket),
         socket_(std::move(socket)),
@@ -139,8 +139,8 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> response_task_runner_;
   base::WeakPtr<AndroidWebSocket> weak_socket_;
-  scoped_ptr<net::StreamSocket> socket_;
-  scoped_ptr<net::WebSocketEncoder> encoder_;
+  std::unique_ptr<net::StreamSocket> socket_;
+  std::unique_ptr<net::WebSocketEncoder> encoder_;
   std::string response_buffer_;
   std::string request_buffer_;
   base::ThreadChecker thread_checker_;
@@ -184,7 +184,7 @@
     int result,
     const std::string& extensions,
     const std::string& body_head,
-    scoped_ptr<net::StreamSocket> socket) {
+    std::unique_ptr<net::StreamSocket> socket) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (result != net::OK || !socket.get()) {
     OnSocketClosed();
diff --git a/chrome/browser/devtools/device/cast_device_provider.cc b/chrome/browser/devtools/device/cast_device_provider.cc
index 6ad7a5f..d06199c 100644
--- a/chrome/browser/devtools/device/cast_device_provider.cc
+++ b/chrome/browser/devtools/device/cast_device_provider.cc
@@ -31,9 +31,9 @@
 // Parses TXT record strings into a map. TXT key-value strings are assumed to
 // follow the form "$key(=$value)?", where $key must contain at least one
 // character, and $value may be empty.
-scoped_ptr<ServiceTxtRecordMap> ParseServiceTxtRecord(
+std::unique_ptr<ServiceTxtRecordMap> ParseServiceTxtRecord(
     const std::vector<std::string>& record) {
-  scoped_ptr<ServiceTxtRecordMap> record_map(new ServiceTxtRecordMap());
+  std::unique_ptr<ServiceTxtRecordMap> record_map(new ServiceTxtRecordMap());
   for (const auto& key_value_str : record) {
     if (key_value_str.empty())
       continue;
@@ -54,7 +54,7 @@
 
 AndroidDeviceManager::DeviceInfo ServiceDescriptionToDeviceInfo(
     const ServiceDescription& service_description) {
-  scoped_ptr<ServiceTxtRecordMap> record_map =
+  std::unique_ptr<ServiceTxtRecordMap> record_map =
       ParseServiceTxtRecord(service_description.metadata);
 
   AndroidDeviceManager::DeviceInfo device_info;
@@ -133,7 +133,7 @@
   // messages will be posted).
   scoped_refptr<base::SingleThreadTaskRunner> runner_;
   scoped_refptr<ServiceDiscoverySharedClient> service_discovery_client_;
-  scoped_ptr<ServiceDiscoveryDeviceLister> device_lister_;
+  std::unique_ptr<ServiceDiscoveryDeviceLister> device_lister_;
 };
 
 CastDeviceProvider::CastDeviceProvider() : weak_factory_(this) {}
diff --git a/chrome/browser/devtools/device/cast_device_provider.h b/chrome/browser/devtools/device/cast_device_provider.h
index d0a82ac3..f0462ca 100644
--- a/chrome/browser/devtools/device/cast_device_provider.h
+++ b/chrome/browser/devtools/device/cast_device_provider.h
@@ -6,11 +6,11 @@
 #define CHROME_BROWSER_DEVTOOLS_DEVICE_CAST_DEVICE_PROVIDER_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/devtools/device/android_device_manager.h"
 #include "chrome/browser/devtools/device/tcp_device_provider.h"
@@ -46,7 +46,8 @@
   ~CastDeviceProvider() override;
 
   scoped_refptr<TCPDeviceProvider> tcp_provider_;
-  scoped_ptr<DeviceListerDelegate, content::BrowserThread::DeleteOnUIThread>
+  std::unique_ptr<DeviceListerDelegate,
+                  content::BrowserThread::DeleteOnUIThread>
       lister_delegate_;
 
   // Keyed on the hostname (IP address).
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.cc b/chrome/browser/devtools/device/devtools_android_bridge.cc
index 0cb4456..11d50ca 100644
--- a/chrome/browser/devtools/device/devtools_android_bridge.cc
+++ b/chrome/browser/devtools/device/devtools_android_bridge.cc
@@ -160,7 +160,7 @@
   if (result < 0)
     return;
   // Parse version, append to package name if available,
-  scoped_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
   base::DictionaryValue* dict;
   if (value && value->GetAsDictionary(&dict)) {
     std::string browser_name;
@@ -187,7 +187,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (result < 0)
     return;
-  scoped_ptr<base::Value> value = base::JSONReader::Read(response);
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(response);
   base::ListValue* list_value;
   if (value && value->GetAsList(&list_value)) {
     for (const auto& page_value : *list_value) {
@@ -220,7 +220,7 @@
 
   const std::string command_;
   const base::Closure callback_;
-  scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
+  std::unique_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
 
   DISALLOW_COPY_AND_ASSIGN(ProtocolCommand);
 };
@@ -315,7 +315,7 @@
   bool socket_opened_;
   std::vector<std::string> pending_messages_;
   scoped_refptr<AndroidDeviceManager::Device> device_;
-  scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
+  std::unique_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
   content::DevToolsAgentHost* agent_host_;
   content::DevToolsExternalAgentProxy* proxy_;
   DISALLOW_COPY_AND_ASSIGN(AgentHostDelegate);
@@ -625,7 +625,7 @@
     const BrowserId& browser_id,
     const std::string& target_path,
     const std::string& method,
-    scoped_ptr<base::DictionaryValue> params,
+    std::unique_ptr<base::DictionaryValue> params,
     const base::Closure callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (target_path.empty())
diff --git a/chrome/browser/devtools/device/devtools_android_bridge.h b/chrome/browser/devtools/device/devtools_android_bridge.h
index 9418983..e716b33 100644
--- a/chrome/browser/devtools/device/devtools_android_bridge.h
+++ b/chrome/browser/devtools/device/devtools_android_bridge.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVICE_DEVTOOLS_ANDROID_BRIDGE_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVICE_DEVTOOLS_ANDROID_BRIDGE_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -12,7 +13,6 @@
 #include "base/cancelable_callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/devtools/device/android_device_manager.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
@@ -78,7 +78,7 @@
 
     BrowserId browser_id_;
     std::string frontend_url_;
-    scoped_ptr<base::DictionaryValue> dict_;
+    std::unique_ptr<base::DictionaryValue> dict_;
 
     DISALLOW_COPY_AND_ASSIGN(RemotePage);
   };
@@ -258,7 +258,7 @@
   void SendProtocolCommand(const BrowserId& browser_id,
                            const std::string& target_path,
                            const std::string& method,
-                           scoped_ptr<base::DictionaryValue> params,
+                           std::unique_ptr<base::DictionaryValue> params,
                            const base::Closure callback);
 
   scoped_refptr<AndroidDeviceManager::Device> FindDevice(
@@ -269,7 +269,7 @@
   }
 
   Profile* const profile_;
-  const scoped_ptr<AndroidDeviceManager> device_manager_;
+  const std::unique_ptr<AndroidDeviceManager> device_manager_;
 
   typedef std::map<std::string, scoped_refptr<AndroidDeviceManager::Device>>
       DeviceMap;
@@ -289,7 +289,7 @@
 
   typedef std::vector<PortForwardingListener*> PortForwardingListeners;
   PortForwardingListeners port_forwarding_listeners_;
-  scoped_ptr<PortForwardingController> port_forwarding_controller_;
+  std::unique_ptr<PortForwardingController> port_forwarding_controller_;
 
   PrefChangeRegistrar pref_change_registrar_;
 
diff --git a/chrome/browser/devtools/device/port_forwarding_browsertest.cc b/chrome/browser/devtools/device/port_forwarding_browsertest.cc
index 8732ae45..14358e5 100644
--- a/chrome/browser/devtools/device/port_forwarding_browsertest.cc
+++ b/chrome/browser/devtools/device/port_forwarding_browsertest.cc
@@ -174,7 +174,7 @@
       forwarding_port, original_url.host() + ":" + original_url.port());
   prefs->Set(prefs::kDevToolsPortForwardingConfig, config);
 
-  scoped_ptr<Listener> wait_for_port_forwarding(new Listener(profile));
+  std::unique_ptr<Listener> wait_for_port_forwarding(new Listener(profile));
   content::RunMessageLoop();
 
   self_provider->set_release_callback_for_test(
diff --git a/chrome/browser/devtools/device/port_forwarding_controller.cc b/chrome/browser/devtools/device/port_forwarding_controller.cc
index 76f983a..29188b4 100644
--- a/chrome/browser/devtools/device/port_forwarding_controller.cc
+++ b/chrome/browser/devtools/device/port_forwarding_controller.cc
@@ -52,13 +52,13 @@
   static void StartTunnel(const std::string& host,
                           int port,
                           int result,
-                          scoped_ptr<net::StreamSocket> socket) {
+                          std::unique_ptr<net::StreamSocket> socket) {
     if (result == net::OK)
       new SocketTunnel(std::move(socket), host, port);
   }
 
  private:
-  SocketTunnel(scoped_ptr<net::StreamSocket> socket,
+  SocketTunnel(std::unique_ptr<net::StreamSocket> socket,
                const std::string& host,
                int port)
       : remote_socket_(std::move(socket)),
@@ -183,9 +183,9 @@
     delete this;
   }
 
-  scoped_ptr<net::StreamSocket> remote_socket_;
-  scoped_ptr<net::StreamSocket> host_socket_;
-  scoped_ptr<net::HostResolver> host_resolver_;
+  std::unique_ptr<net::StreamSocket> remote_socket_;
+  std::unique_ptr<net::StreamSocket> host_socket_;
+  std::unique_ptr<net::HostResolver> host_resolver_;
   net::AddressList address_list_;
   int pending_writes_;
   bool pending_destruction_;
@@ -235,7 +235,7 @@
 
   PortForwardingController* controller_;
   scoped_refptr<DevToolsAndroidBridge::RemoteBrowser> browser_;
-  scoped_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
+  std::unique_ptr<AndroidDeviceManager::AndroidWebSocket> web_socket_;
   int command_id_;
   bool connected_;
   ForwardingMap forwarding_map_;
@@ -303,7 +303,7 @@
 void PortForwardingController::Connection::SendCommand(
     const std::string& method, int port) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue);
+  std::unique_ptr<base::DictionaryValue> params(new base::DictionaryValue);
   if (method == tethering::bind::kName) {
     params->SetInteger(tethering::bind::kParamPort, port);
   } else {
@@ -394,7 +394,7 @@
     return;
 
   std::string method;
-  scoped_ptr<base::DictionaryValue> params;
+  std::unique_ptr<base::DictionaryValue> params;
   if (!DevToolsProtocol::ParseNotification(message, &method, &params))
     return;
 
diff --git a/chrome/browser/devtools/device/tcp_device_provider.cc b/chrome/browser/devtools/device/tcp_device_provider.cc
index fce75f0..3504f54 100644
--- a/chrome/browser/devtools/device/tcp_device_provider.cc
+++ b/chrome/browser/devtools/device/tcp_device_provider.cc
@@ -24,7 +24,7 @@
 
 static void RunSocketCallback(
     const AndroidDeviceManager::SocketCallback& callback,
-    scoped_ptr<net::StreamSocket> socket,
+    std::unique_ptr<net::StreamSocket> socket,
     int result) {
   callback.Run(result, std::move(socket));
 }
@@ -52,14 +52,14 @@
       delete this;
       return;
     }
-    scoped_ptr<net::StreamSocket> socket(
+    std::unique_ptr<net::StreamSocket> socket(
         new net::TCPClientSocket(address_list_, NULL, net::NetLog::Source()));
     socket->Connect(
         base::Bind(&RunSocketCallback, callback_, base::Passed(&socket)));
     delete this;
   }
 
-  scoped_ptr<net::HostResolver> host_resolver_;
+  std::unique_ptr<net::HostResolver> host_resolver_;
   net::AddressList address_list_;
   AdbClientSocket::SocketCallback callback_;
 };
diff --git a/chrome/browser/devtools/device/usb/android_rsa.cc b/chrome/browser/devtools/device/usb/android_rsa.cc
index e260345..e89e250 100644
--- a/chrome/browser/devtools/device/usb/android_rsa.cc
+++ b/chrome/browser/devtools/device/usb/android_rsa.cc
@@ -9,9 +9,9 @@
 #include <string.h>
 
 #include <limits>
+#include <memory>
 
 #include "base/base64.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
 #include "components/syncable_prefs/pref_service_syncable.h"
@@ -194,7 +194,7 @@
   std::string encoded_key =
       profile->GetPrefs()->GetString(prefs::kDevToolsAdbKey);
   std::string decoded_key;
-  scoped_ptr<crypto::RSAPrivateKey> key;
+  std::unique_ptr<crypto::RSAPrivateKey> key;
   if (!encoded_key.empty() && base::Base64Decode(encoded_key, &decoded_key)) {
     std::vector<uint8_t> key_info(decoded_key.begin(), decoded_key.end());
     key.reset(crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(key_info));
diff --git a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
index 294cb66..bb85e3b 100644
--- a/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_browsertest.cc
@@ -4,11 +4,13 @@
 
 #include <stddef.h>
 #include <stdint.h>
+
 #include <algorithm>
 #include <utility>
 
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/location.h"
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
@@ -116,7 +118,7 @@
   }
 
   Callback callback_;
-  scoped_ptr<MockAndroidConnection> connection_;
+  std::unique_ptr<MockAndroidConnection> connection_;
 };
 
 template <class T>
@@ -299,14 +301,12 @@
                       std::string());
         local_sockets_.set(
             current_message_->arg0,
-            make_scoped_ptr(new MockLocalSocket(
+            base::WrapUnique(new MockLocalSocket(
                 base::Bind(&MockUsbDeviceHandle::WriteResponse,
-                           base::Unretained(this),
-                           last_local_socket_,
+                           base::Unretained(this), last_local_socket_,
                            current_message_->arg0),
-                kDeviceSerial,
-                current_message_->body.substr(
-                    0, current_message_->body.size() - 1))));
+                kDeviceSerial, current_message_->body.substr(
+                                   0, current_message_->body.size() - 1))));
         return;
       }
       default: {
@@ -384,10 +384,10 @@
 
   scoped_refptr<MockUsbDevice<T> > device_;
   uint32_t remaining_body_length_;
-  scoped_ptr<AdbMessage> current_message_;
+  std::unique_ptr<AdbMessage> current_message_;
   std::vector<char> output_buffer_;
   std::queue<Query> queries_;
-  base::ScopedPtrHashMap<int, scoped_ptr<MockLocalSocket>> local_sockets_;
+  base::ScopedPtrHashMap<int, std::unique_ptr<MockLocalSocket>> local_sockets_;
   int last_local_socket_;
   bool broken_;
 };
@@ -508,14 +508,14 @@
 
 class TestDeviceClient : public DeviceClient {
  public:
-  explicit TestDeviceClient(scoped_ptr<UsbService> service)
+  explicit TestDeviceClient(std::unique_ptr<UsbService> service)
       : DeviceClient(), usb_service_(std::move(service)) {}
   ~TestDeviceClient() override {}
 
  private:
   UsbService* GetUsbService() override { return usb_service_.get(); }
 
-  scoped_ptr<UsbService> usb_service_;
+  std::unique_ptr<UsbService> usb_service_;
 };
 
 class DevToolsAndroidBridgeWarmUp
@@ -563,12 +563,12 @@
     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, request);
   }
 
-  virtual scoped_ptr<MockUsbService> CreateMockService() {
-    return make_scoped_ptr(new MockUsbService());
+  virtual std::unique_ptr<MockUsbService> CreateMockService() {
+    return base::WrapUnique(new MockUsbService());
   }
 
   scoped_refptr<content::MessageLoopRunner> runner_;
-  scoped_ptr<TestDeviceClient> device_client_;
+  std::unique_ptr<TestDeviceClient> device_client_;
   DevToolsAndroidBridge* adb_bridge_;
   int scheduler_invoked_;
 };
@@ -586,22 +586,22 @@
 
 class AndroidUsbTraitsTest : public AndroidUsbDiscoveryTest {
  protected:
-  scoped_ptr<MockUsbService> CreateMockService() override {
-    return make_scoped_ptr(new MockUsbServiceForCheckingTraits());
+  std::unique_ptr<MockUsbService> CreateMockService() override {
+    return base::WrapUnique(new MockUsbServiceForCheckingTraits());
   }
 };
 
 class AndroidBreakingUsbTest : public AndroidUsbDiscoveryTest {
  protected:
-  scoped_ptr<MockUsbService> CreateMockService() override {
-    return make_scoped_ptr(new MockBreakingUsbService());
+  std::unique_ptr<MockUsbService> CreateMockService() override {
+    return base::WrapUnique(new MockBreakingUsbService());
   }
 };
 
 class AndroidNoConfigUsbTest : public AndroidUsbDiscoveryTest {
  protected:
-  scoped_ptr<MockUsbService> CreateMockService() override {
-    return make_scoped_ptr(new MockNoConfigUsbService());
+  std::unique_ptr<MockUsbService> CreateMockService() override {
+    return base::WrapUnique(new MockNoConfigUsbService());
   }
 };
 
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.cc b/chrome/browser/devtools/device/usb/android_usb_device.cc
index 8e655a6..919cc90 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_device.cc
@@ -10,6 +10,7 @@
 #include "base/barrier_closure.h"
 #include "base/base64.h"
 #include "base/lazy_instance.h"
+#include "base/memory/ptr_util.h"
 #include "base/single_thread_task_runner.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
@@ -141,7 +142,7 @@
 
 void RespondOnCallerThread(const AndroidUsbDevicesCallback& callback,
                            AndroidUsbDevices* new_devices) {
-  scoped_ptr<AndroidUsbDevices> devices(new_devices);
+  std::unique_ptr<AndroidUsbDevices> devices(new_devices);
 
   // Add raw pointers to the newly claimed devices.
   for (const scoped_refptr<AndroidUsbDevice>& device : *devices) {
@@ -359,8 +360,8 @@
   if (task_runner_)
     return;
   task_runner_ = base::ThreadTaskRunnerHandle::Get();
-  Queue(make_scoped_ptr(new AdbMessage(AdbMessage::kCommandCNXN, kVersion,
-                                       kMaxPayload, kHostConnectMessage)));
+  Queue(base::WrapUnique(new AdbMessage(AdbMessage::kCommandCNXN, kVersion,
+                                        kMaxPayload, kHostConnectMessage)));
   ReadHeader();
 }
 
@@ -378,7 +379,8 @@
                             uint32_t arg0,
                             uint32_t arg1,
                             const std::string& body) {
-  scoped_ptr<AdbMessage> message(new AdbMessage(command, arg0, arg1, body));
+  std::unique_ptr<AdbMessage> message(
+      new AdbMessage(command, arg0, arg1, body));
   // Delay open request if not yet connected.
   if (!is_connected_) {
     pending_messages_.push_back(message.release());
@@ -392,7 +394,7 @@
   Terminate();
 }
 
-void AndroidUsbDevice::Queue(scoped_ptr<AdbMessage> message) {
+void AndroidUsbDevice::Queue(std::unique_ptr<AdbMessage> message) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   // Queue header.
@@ -495,7 +497,7 @@
   DumpMessage(false, buffer->data(), result);
   std::vector<uint32_t> header(6);
   memcpy(&header[0], buffer->data(), result);
-  scoped_ptr<AdbMessage> message(
+  std::unique_ptr<AdbMessage> message(
       new AdbMessage(header[0], header[1], header[2], ""));
   uint32_t data_length = header[3];
   uint32_t data_check = header[4];
@@ -516,7 +518,7 @@
   }
 }
 
-void AndroidUsbDevice::ReadBody(scoped_ptr<AdbMessage> message,
+void AndroidUsbDevice::ReadBody(std::unique_ptr<AdbMessage> message,
                                 uint32_t data_length,
                                 uint32_t data_check) {
   DCHECK(task_runner_->BelongsToCurrentThread());
@@ -534,7 +536,7 @@
                  base::Passed(&message), data_length, data_check));
 }
 
-void AndroidUsbDevice::ParseBody(scoped_ptr<AdbMessage> message,
+void AndroidUsbDevice::ParseBody(std::unique_ptr<AdbMessage> message,
                                  uint32_t data_length,
                                  uint32_t data_check,
                                  UsbTransferStatus status,
@@ -567,7 +569,7 @@
                                     base::Passed(&message)));
 }
 
-void AndroidUsbDevice::HandleIncoming(scoped_ptr<AdbMessage> message) {
+void AndroidUsbDevice::HandleIncoming(std::unique_ptr<AdbMessage> message) {
   DCHECK(task_runner_->BelongsToCurrentThread());
 
   switch (message->command) {
@@ -575,21 +577,19 @@
       {
       DCHECK_EQ(message->arg0, static_cast<uint32_t>(AdbMessage::kAuthToken));
         if (signature_sent_) {
-          Queue(make_scoped_ptr(new AdbMessage(
-              AdbMessage::kCommandAUTH,
-              AdbMessage::kAuthRSAPublicKey, 0,
+          Queue(base::WrapUnique(new AdbMessage(
+              AdbMessage::kCommandAUTH, AdbMessage::kAuthRSAPublicKey, 0,
               AndroidRSAPublicKey(rsa_key_.get()))));
         } else {
           signature_sent_ = true;
           std::string signature = AndroidRSASign(rsa_key_.get(), message->body);
           if (!signature.empty()) {
-            Queue(make_scoped_ptr(new AdbMessage(AdbMessage::kCommandAUTH,
-                                                 AdbMessage::kAuthSignature, 0,
-                                                 signature)));
+            Queue(base::WrapUnique(new AdbMessage(AdbMessage::kCommandAUTH,
+                                                  AdbMessage::kAuthSignature, 0,
+                                                  signature)));
           } else {
-            Queue(make_scoped_ptr(new AdbMessage(
-                AdbMessage::kCommandAUTH,
-                AdbMessage::kAuthRSAPublicKey, 0,
+            Queue(base::WrapUnique(new AdbMessage(
+                AdbMessage::kCommandAUTH, AdbMessage::kAuthRSAPublicKey, 0,
                 AndroidRSAPublicKey(rsa_key_.get()))));
           }
         }
@@ -602,7 +602,7 @@
         pending.swap(pending_messages_);
         for (PendingMessages::iterator it = pending.begin();
              it != pending.end(); ++it) {
-          Queue(make_scoped_ptr(*it));
+          Queue(base::WrapUnique(*it));
         }
       }
       break;
diff --git a/chrome/browser/devtools/device/usb/android_usb_device.h b/chrome/browser/devtools/device/usb/android_usb_device.h
index 31c0af0..62294974 100644
--- a/chrome/browser/devtools/device/usb/android_usb_device.h
+++ b/chrome/browser/devtools/device/usb/android_usb_device.h
@@ -9,12 +9,12 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <queue>
 #include <vector>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/scoped_vector.h"
 #include "base/memory/weak_ptr.h"
 #include "device/usb/usb_device_handle.h"
@@ -106,7 +106,7 @@
   friend class base::RefCountedThreadSafe<AndroidUsbDevice>;
   virtual ~AndroidUsbDevice();
 
-  void Queue(scoped_ptr<AdbMessage> message);
+  void Queue(std::unique_ptr<AdbMessage> message);
   void ProcessOutgoing();
   void OutgoingMessageSent(device::UsbTransferStatus status,
                            scoped_refptr<net::IOBuffer> buffer,
@@ -117,17 +117,17 @@
                    scoped_refptr<net::IOBuffer> buffer,
                    size_t result);
 
-  void ReadBody(scoped_ptr<AdbMessage> message,
+  void ReadBody(std::unique_ptr<AdbMessage> message,
                 uint32_t data_length,
                 uint32_t data_check);
-  void ParseBody(scoped_ptr<AdbMessage> message,
+  void ParseBody(std::unique_ptr<AdbMessage> message,
                  uint32_t data_length,
                  uint32_t data_check,
                  device::UsbTransferStatus status,
                  scoped_refptr<net::IOBuffer> buffer,
                  size_t result);
 
-  void HandleIncoming(scoped_ptr<AdbMessage> message);
+  void HandleIncoming(std::unique_ptr<AdbMessage> message);
 
   void TransferError(device::UsbTransferStatus status);
 
@@ -138,7 +138,7 @@
 
   scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
 
-  scoped_ptr<crypto::RSAPrivateKey> rsa_key_;
+  std::unique_ptr<crypto::RSAPrivateKey> rsa_key_;
 
   // Device info
   scoped_refptr<device::UsbDeviceHandle> usb_handle_;
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.cc b/chrome/browser/devtools/device/usb/android_usb_socket.cc
index 929f99a..f70a6cb 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.cc
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.cc
@@ -39,7 +39,7 @@
     delete_callback_.Run();
 }
 
-void AndroidUsbSocket::HandleIncoming(scoped_ptr<AdbMessage> message) {
+void AndroidUsbSocket::HandleIncoming(std::unique_ptr<AdbMessage> message) {
   if (!device_.get())
     return;
 
diff --git a/chrome/browser/devtools/device/usb/android_usb_socket.h b/chrome/browser/devtools/device/usb/android_usb_socket.h
index 1c2e559..da57f62 100644
--- a/chrome/browser/devtools/device/usb/android_usb_socket.h
+++ b/chrome/browser/devtools/device/usb/android_usb_socket.h
@@ -28,7 +28,7 @@
                    base::Closure delete_callback);
   ~AndroidUsbSocket() override;
 
-  void HandleIncoming(scoped_ptr<AdbMessage> message);
+  void HandleIncoming(std::unique_ptr<AdbMessage> message);
 
   void Terminated(bool closed_by_device);
 
diff --git a/chrome/browser/devtools/device/usb/usb_device_provider.cc b/chrome/browser/devtools/device/usb/usb_device_provider.cc
index 7475823b..5da8c614 100644
--- a/chrome/browser/devtools/device/usb/usb_device_provider.cc
+++ b/chrome/browser/devtools/device/usb/usb_device_provider.cc
@@ -6,6 +6,7 @@
 
 #include <utility>
 
+#include "base/memory/ptr_util.h"
 #include "base/strings/stringprintf.h"
 #include "chrome/browser/devtools/device/usb/android_rsa.h"
 #include "chrome/browser/devtools/device/usb/android_usb_device.h"
@@ -23,7 +24,7 @@
 void OnOpenSocket(const UsbDeviceProvider::SocketCallback& callback,
                   net::StreamSocket* socket_raw,
                   int result) {
-  scoped_ptr<net::StreamSocket> socket(socket_raw);
+  std::unique_ptr<net::StreamSocket> socket(socket_raw);
   if (result != net::OK)
     socket.reset();
   callback.Run(result, std::move(socket));
@@ -115,7 +116,7 @@
   UsbDeviceMap::iterator it = device_map_.find(serial);
   if (it == device_map_.end()) {
     callback.Run(net::ERR_CONNECTION_FAILED,
-                 make_scoped_ptr<net::StreamSocket>(NULL));
+                 base::WrapUnique<net::StreamSocket>(NULL));
     return;
   }
   std::string socket_name =
@@ -123,12 +124,12 @@
   net::StreamSocket* socket = it->second->CreateSocket(socket_name);
   if (!socket) {
     callback.Run(net::ERR_CONNECTION_FAILED,
-                 make_scoped_ptr<net::StreamSocket>(NULL));
+                 base::WrapUnique<net::StreamSocket>(NULL));
     return;
   }
   int result = socket->Connect(base::Bind(&OnOpenSocket, callback, socket));
   if (result != net::ERR_IO_PENDING)
-    callback.Run(result, make_scoped_ptr<net::StreamSocket>(NULL));
+    callback.Run(result, base::WrapUnique<net::StreamSocket>(NULL));
 }
 
 void UsbDeviceProvider::ReleaseDevice(const std::string& serial) {
diff --git a/chrome/browser/devtools/device/usb/usb_device_provider.h b/chrome/browser/devtools/device/usb/usb_device_provider.h
index 2d77e20..02d06843 100644
--- a/chrome/browser/devtools/device/usb/usb_device_provider.h
+++ b/chrome/browser/devtools/device/usb/usb_device_provider.h
@@ -39,7 +39,7 @@
 
   typedef std::map<std::string, scoped_refptr<AndroidUsbDevice> > UsbDeviceMap;
 
-  scoped_ptr<crypto::RSAPrivateKey>  rsa_key_;
+  std::unique_ptr<crypto::RSAPrivateKey> rsa_key_;
   UsbDeviceMap device_map_;
 };
 
diff --git a/chrome/browser/devtools/devtools_file_helper.h b/chrome/browser/devtools/devtools_file_helper.h
index c63ffa5..4e9d7799 100644
--- a/chrome/browser/devtools/devtools_file_helper.h
+++ b/chrome/browser/devtools/devtools_file_helper.h
@@ -6,6 +6,7 @@
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_FILE_HELPER_H_
 
 #include <map>
+#include <memory>
 #include <set>
 #include <string>
 #include <vector>
@@ -13,7 +14,6 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "components/prefs/pref_change_registrar.h"
@@ -141,7 +141,7 @@
   PathsMap saved_files_;
   PrefChangeRegistrar pref_change_registrar_;
   std::set<std::string> file_system_paths_;
-  scoped_ptr<DevToolsFileWatcher> file_watcher_;
+  std::unique_ptr<DevToolsFileWatcher> file_watcher_;
   base::WeakPtrFactory<DevToolsFileHelper> weak_factory_;
   DISALLOW_COPY_AND_ASSIGN(DevToolsFileHelper);
 };
diff --git a/chrome/browser/devtools/devtools_file_system_indexer.h b/chrome/browser/devtools/devtools_file_system_indexer.h
index 7682c49..ade1bc8 100644
--- a/chrome/browser/devtools/devtools_file_system_indexer.h
+++ b/chrome/browser/devtools/devtools_file_system_indexer.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <map>
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -15,7 +16,6 @@
 #include "base/files/file_proxy.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 
 class Profile;
 
@@ -69,7 +69,7 @@
     TotalWorkCallback total_work_callback_;
     WorkedCallback worked_callback_;
     DoneCallback done_callback_;
-    scoped_ptr<base::FileEnumerator> file_enumerator_;
+    std::unique_ptr<base::FileEnumerator> file_enumerator_;
     typedef std::map<base::FilePath, base::Time> FilePathTimesMap;
     FilePathTimesMap file_path_times_;
     FilePathTimesMap::const_iterator indexing_it_;
diff --git a/chrome/browser/devtools/devtools_file_watcher.cc b/chrome/browser/devtools/devtools_file_watcher.cc
index 6cfafcd..b92f146 100644
--- a/chrome/browser/devtools/devtools_file_watcher.cc
+++ b/chrome/browser/devtools/devtools_file_watcher.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <map>
+#include <memory>
 #include <set>
 
 #include "base/bind.h"
@@ -13,7 +14,6 @@
 #include "base/files/file_path.h"
 #include "base/files/file_path_watcher.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
@@ -42,7 +42,7 @@
   void DispatchNotifications();
 
   std::vector<DevToolsFileWatcher*> listeners_;
-  std::map<base::FilePath, scoped_ptr<base::FilePathWatcher>> watchers_;
+  std::map<base::FilePath, std::unique_ptr<base::FilePathWatcher>> watchers_;
   using FilePathTimesMap = std::map<base::FilePath, base::Time>;
   FilePathTimesMap file_path_times_;
   std::set<base::FilePath> pending_paths_;
diff --git a/chrome/browser/devtools/devtools_network_controller.cc b/chrome/browser/devtools/devtools_network_controller.cc
index b83ac97..66c8ee0 100644
--- a/chrome/browser/devtools/devtools_network_controller.cc
+++ b/chrome/browser/devtools/devtools_network_controller.cc
@@ -32,7 +32,7 @@
 
 void DevToolsNetworkController::SetNetworkState(
     const std::string& client_id,
-    scoped_ptr<DevToolsNetworkConditions> conditions) {
+    std::unique_ptr<DevToolsNetworkConditions> conditions) {
   DCHECK(thread_checker_.CalledOnValidThread());
 
   DevToolsNetworkInterceptor* interceptor = interceptors_.get(client_id);
@@ -40,13 +40,13 @@
     DCHECK(conditions);
     if (!conditions)
       return;
-    scoped_ptr<DevToolsNetworkInterceptor> new_interceptor(
+    std::unique_ptr<DevToolsNetworkInterceptor> new_interceptor(
         new DevToolsNetworkInterceptor());
     new_interceptor->UpdateConditions(std::move(conditions));
     interceptors_.set(client_id, std::move(new_interceptor));
   } else {
     if (!conditions) {
-      scoped_ptr<DevToolsNetworkConditions> online_conditions(
+      std::unique_ptr<DevToolsNetworkConditions> online_conditions(
           new DevToolsNetworkConditions());
       interceptor->UpdateConditions(std::move(online_conditions));
       interceptors_.erase(client_id);
@@ -66,7 +66,7 @@
 
   bool is_appcache_offline = appcache_interceptor_->IsOffline();
   if (is_appcache_offline != has_offline_interceptors) {
-    scoped_ptr<DevToolsNetworkConditions> appcache_conditions(
+    std::unique_ptr<DevToolsNetworkConditions> appcache_conditions(
         new DevToolsNetworkConditions(has_offline_interceptors));
     appcache_interceptor_->UpdateConditions(std::move(appcache_conditions));
   }
diff --git a/chrome/browser/devtools/devtools_network_controller.h b/chrome/browser/devtools/devtools_network_controller.h
index 89fa2fb1..4661f6f 100644
--- a/chrome/browser/devtools/devtools_network_controller.h
+++ b/chrome/browser/devtools/devtools_network_controller.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_H_
 
+#include <memory>
 #include <string>
 
 #include "base/containers/scoped_ptr_hash_map.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/threading/thread_checker.h"
 
 class DevToolsNetworkConditions;
@@ -23,9 +23,8 @@
   virtual ~DevToolsNetworkController();
 
   // Applies network emulation configuration.
-  void SetNetworkState(
-      const std::string& client_id,
-      scoped_ptr<DevToolsNetworkConditions> conditions);
+  void SetNetworkState(const std::string& client_id,
+                       std::unique_ptr<DevToolsNetworkConditions> conditions);
 
   DevToolsNetworkInterceptor* GetInterceptor(
       const std::string& client_id);
@@ -33,9 +32,9 @@
  private:
   using InterceptorMap =
       base::ScopedPtrHashMap<std::string,
-                             scoped_ptr<DevToolsNetworkInterceptor>>;
+                             std::unique_ptr<DevToolsNetworkInterceptor>>;
 
-  scoped_ptr<DevToolsNetworkInterceptor> appcache_interceptor_;
+  std::unique_ptr<DevToolsNetworkInterceptor> appcache_interceptor_;
   InterceptorMap interceptors_;
   base::ThreadChecker thread_checker_;
 
diff --git a/chrome/browser/devtools/devtools_network_controller_handle.cc b/chrome/browser/devtools/devtools_network_controller_handle.cc
index d2606fe..b5bc621 100644
--- a/chrome/browser/devtools/devtools_network_controller_handle.cc
+++ b/chrome/browser/devtools/devtools_network_controller_handle.cc
@@ -21,7 +21,7 @@
 
 void DevToolsNetworkControllerHandle::SetNetworkState(
     const std::string& client_id,
-    scoped_ptr<DevToolsNetworkConditions> conditions) {
+    std::unique_ptr<DevToolsNetworkConditions> conditions) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   BrowserThread::PostTask(
@@ -46,7 +46,7 @@
 
 void DevToolsNetworkControllerHandle::SetNetworkStateOnIO(
     const std::string& client_id,
-    scoped_ptr<DevToolsNetworkConditions> conditions) {
+    std::unique_ptr<DevToolsNetworkConditions> conditions) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   LazyInitialize();
diff --git a/chrome/browser/devtools/devtools_network_controller_handle.h b/chrome/browser/devtools/devtools_network_controller_handle.h
index 7aee0ff5..e818204 100644
--- a/chrome/browser/devtools/devtools_network_controller_handle.h
+++ b/chrome/browser/devtools/devtools_network_controller_handle.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_HANDLE_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_CONTROLLER_HANDLE_H_
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 
 class DevToolsNetworkConditions;
 class DevToolsNetworkController;
@@ -23,17 +23,18 @@
 
   // Called on the UI thread.
   void SetNetworkState(const std::string& client_id,
-                       scoped_ptr<DevToolsNetworkConditions> conditions);
+                       std::unique_ptr<DevToolsNetworkConditions> conditions);
 
   // Called on the IO thread.
   DevToolsNetworkController* GetController();
 
  private:
   void LazyInitialize();
-  void SetNetworkStateOnIO(const std::string& client_id,
-                           scoped_ptr<DevToolsNetworkConditions> conditions);
+  void SetNetworkStateOnIO(
+      const std::string& client_id,
+      std::unique_ptr<DevToolsNetworkConditions> conditions);
 
-  scoped_ptr<DevToolsNetworkController> controller_;
+  std::unique_ptr<DevToolsNetworkController> controller_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkControllerHandle);
 };
diff --git a/chrome/browser/devtools/devtools_network_controller_unittest.cc b/chrome/browser/devtools/devtools_network_controller_unittest.cc
index d0759bb..0e51b24f 100644
--- a/chrome/browser/devtools/devtools_network_controller_unittest.cc
+++ b/chrome/browser/devtools/devtools_network_controller_unittest.cc
@@ -5,12 +5,13 @@
 #include "chrome/browser/devtools/devtools_network_controller.h"
 
 #include <stdint.h>
+
+#include <memory>
 #include <string>
 #include <utility>
 
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "chrome/browser/devtools/devtools_network_conditions.h"
@@ -63,7 +64,7 @@
         "X-DevTools-Emulate-Network-Conditions-Client-Id: 42\r\n";
     AddMockTransaction(&mock_transaction_);
 
-    scoped_ptr<net::HttpTransaction> network_transaction;
+    std::unique_ptr<net::HttpTransaction> network_transaction;
     network_layer_.CreateTransaction(
         net::DEFAULT_PRIORITY, &network_transaction);
     transaction_.reset(new DevToolsNetworkTransaction(
@@ -71,13 +72,13 @@
   }
 
   void SetNetworkState(bool offline, double download, double upload) {
-    scoped_ptr<DevToolsNetworkConditions> conditions(
+    std::unique_ptr<DevToolsNetworkConditions> conditions(
         new DevToolsNetworkConditions(offline, 0, download, upload));
     controller_.SetNetworkState(kClientId, std::move(conditions));
   }
 
   void SetNetworkState(const std::string& id, bool offline) {
-    scoped_ptr<DevToolsNetworkConditions> conditions(
+    std::unique_ptr<DevToolsNetworkConditions> conditions(
         new DevToolsNetworkConditions(offline));
     controller_.SetNetworkState(id, std::move(conditions));
   }
@@ -146,10 +147,10 @@
   net::CompletionCallback completion_callback_;
   MockTransaction mock_transaction_;
   DevToolsNetworkController controller_;
-  scoped_ptr<DevToolsNetworkTransaction> transaction_;
+  std::unique_ptr<DevToolsNetworkTransaction> transaction_;
   scoped_refptr<net::IOBuffer> buffer_;
-  scoped_ptr<net::ChunkedUploadDataStream> upload_data_stream_;
-  scoped_ptr<MockHttpRequest> request_;
+  std::unique_ptr<net::ChunkedUploadDataStream> upload_data_stream_;
+  std::unique_ptr<MockHttpRequest> request_;
 };
 
 TEST(DevToolsNetworkControllerTest, SingleDisableEnable) {
diff --git a/chrome/browser/devtools/devtools_network_interceptor.cc b/chrome/browser/devtools/devtools_network_interceptor.cc
index 0d780272..999ddfe 100644
--- a/chrome/browser/devtools/devtools_network_interceptor.cc
+++ b/chrome/browser/devtools/devtools_network_interceptor.cc
@@ -66,7 +66,7 @@
 }
 
 void DevToolsNetworkInterceptor::UpdateConditions(
-    scoped_ptr<DevToolsNetworkConditions> conditions) {
+    std::unique_ptr<DevToolsNetworkConditions> conditions) {
   DCHECK(conditions);
   base::TimeTicks now = base::TimeTicks::Now();
   if (conditions_->IsThrottling())
diff --git a/chrome/browser/devtools/devtools_network_interceptor.h b/chrome/browser/devtools/devtools_network_interceptor.h
index 05eaa67..34b7399 100644
--- a/chrome/browser/devtools/devtools_network_interceptor.h
+++ b/chrome/browser/devtools/devtools_network_interceptor.h
@@ -7,13 +7,13 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <set>
 #include <string>
 #include <utility>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/timer/timer.h"
 
 class DevToolsNetworkConditions;
@@ -35,7 +35,7 @@
   base::WeakPtr<DevToolsNetworkInterceptor> GetWeakPtr();
 
   // Applies network emulation configuration.
-  void UpdateConditions(scoped_ptr<DevToolsNetworkConditions> conditions);
+  void UpdateConditions(std::unique_ptr<DevToolsNetworkConditions> conditions);
 
   // Throttles with |is_upload == true| always succeed, even in offline mode.
   int StartThrottle(int result,
@@ -78,7 +78,7 @@
 
   void RemoveRecord(ThrottleRecords* records, const ThrottleCallback& callback);
 
-  scoped_ptr<DevToolsNetworkConditions> conditions_;
+  std::unique_ptr<DevToolsNetworkConditions> conditions_;
 
   // Throttables suspended for a "latency" period.
   ThrottleRecords suspended_;
diff --git a/chrome/browser/devtools/devtools_network_protocol_handler.cc b/chrome/browser/devtools/devtools_network_protocol_handler.cc
index 2b7ca3c..be5d0b92 100644
--- a/chrome/browser/devtools/devtools_network_protocol_handler.cc
+++ b/chrome/browser/devtools/devtools_network_protocol_handler.cc
@@ -40,17 +40,17 @@
   return nullptr;
 }
 
-scoped_ptr<base::DictionaryValue>
+std::unique_ptr<base::DictionaryValue>
 DevToolsNetworkProtocolHandler::CanEmulateNetworkConditions(
     content::DevToolsAgentHost* agent_host,
     int command_id,
     base::DictionaryValue* params) {
-  scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
+  std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue());
   result->SetBoolean(chrome::devtools::kResult, true);
   return DevToolsProtocol::CreateSuccessResponse(command_id, std::move(result));
 }
 
-scoped_ptr<base::DictionaryValue>
+std::unique_ptr<base::DictionaryValue>
 DevToolsNetworkProtocolHandler::EmulateNetworkConditions(
     content::DevToolsAgentHost* agent_host,
     int command_id,
@@ -87,17 +87,17 @@
   if (upload_throughput < 0.0)
     upload_throughput = 0.0;
 
-  scoped_ptr<DevToolsNetworkConditions> conditions(
-      new DevToolsNetworkConditions(
-          offline, latency, download_throughput, upload_throughput));
+  std::unique_ptr<DevToolsNetworkConditions> conditions(
+      new DevToolsNetworkConditions(offline, latency, download_throughput,
+                                    upload_throughput));
 
   UpdateNetworkState(agent_host, std::move(conditions));
-  return scoped_ptr<base::DictionaryValue>();
+  return std::unique_ptr<base::DictionaryValue>();
 }
 
 void DevToolsNetworkProtocolHandler::UpdateNetworkState(
     content::DevToolsAgentHost* agent_host,
-    scoped_ptr<DevToolsNetworkConditions> conditions) {
+    std::unique_ptr<DevToolsNetworkConditions> conditions) {
   Profile* profile = Profile::FromBrowserContext(
       agent_host->GetBrowserContext());
   if (!profile)
@@ -109,7 +109,7 @@
 void DevToolsNetworkProtocolHandler::DevToolsAgentStateChanged(
     content::DevToolsAgentHost* agent_host,
     bool attached) {
-  scoped_ptr<DevToolsNetworkConditions> conditions;
+  std::unique_ptr<DevToolsNetworkConditions> conditions;
   if (attached)
     conditions.reset(new DevToolsNetworkConditions());
   UpdateNetworkState(agent_host, std::move(conditions));
diff --git a/chrome/browser/devtools/devtools_network_protocol_handler.h b/chrome/browser/devtools/devtools_network_protocol_handler.h
index a0cdaed82..4f1c16b 100644
--- a/chrome/browser/devtools/devtools_network_protocol_handler.h
+++ b/chrome/browser/devtools/devtools_network_protocol_handler.h
@@ -5,9 +5,10 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_PROTOCOL_HANDLER_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_PROTOCOL_HANDLER_H_
 
+#include <memory>
+
 #include "base/compiler_specific.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/devtools/devtools_protocol.h"
 
 namespace content {
@@ -29,19 +30,19 @@
       base::DictionaryValue* command_dict);
 
  private:
-  scoped_ptr<base::DictionaryValue> CanEmulateNetworkConditions(
+  std::unique_ptr<base::DictionaryValue> CanEmulateNetworkConditions(
       content::DevToolsAgentHost* agent_host,
       int command_id,
       base::DictionaryValue* params);
 
-  scoped_ptr<base::DictionaryValue> EmulateNetworkConditions(
+  std::unique_ptr<base::DictionaryValue> EmulateNetworkConditions(
       content::DevToolsAgentHost* agent_host,
       int command_id,
       base::DictionaryValue* params);
 
   void UpdateNetworkState(
       content::DevToolsAgentHost* agent_host,
-      scoped_ptr<DevToolsNetworkConditions> conditions);
+      std::unique_ptr<DevToolsNetworkConditions> conditions);
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkProtocolHandler);
 };
diff --git a/chrome/browser/devtools/devtools_network_transaction.cc b/chrome/browser/devtools/devtools_network_transaction.cc
index f9b24b7..f60b2ac 100644
--- a/chrome/browser/devtools/devtools_network_transaction.cc
+++ b/chrome/browser/devtools/devtools_network_transaction.cc
@@ -25,7 +25,7 @@
 
 DevToolsNetworkTransaction::DevToolsNetworkTransaction(
     DevToolsNetworkController* controller,
-    scoped_ptr<net::HttpTransaction> network_transaction)
+    std::unique_ptr<net::HttpTransaction> network_transaction)
     : throttled_byte_count_(0),
       controller_(controller),
       network_transaction_(std::move(network_transaction)),
diff --git a/chrome/browser/devtools/devtools_network_transaction.h b/chrome/browser/devtools/devtools_network_transaction.h
index c3a2382..d9f7e92 100644
--- a/chrome/browser/devtools/devtools_network_transaction.h
+++ b/chrome/browser/devtools/devtools_network_transaction.h
@@ -7,8 +7,9 @@
 
 #include <stdint.h>
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/devtools/devtools_network_interceptor.h"
 #include "net/base/completion_callback.h"
@@ -51,7 +52,7 @@
 
   DevToolsNetworkTransaction(
       DevToolsNetworkController* controller,
-      scoped_ptr<net::HttpTransaction> network_transaction);
+      std::unique_ptr<net::HttpTransaction> network_transaction);
 
   ~DevToolsNetworkTransaction() override;
 
@@ -117,13 +118,13 @@
   base::WeakPtr<DevToolsNetworkInterceptor> interceptor_;
 
   // Modified upload data stream. Should be destructed after |custom_request_|.
-  scoped_ptr<DevToolsNetworkUploadDataStream> custom_upload_data_stream_;
+  std::unique_ptr<DevToolsNetworkUploadDataStream> custom_upload_data_stream_;
 
   // Modified request. Should be destructed after |network_transaction_|.
-  scoped_ptr<net::HttpRequestInfo> custom_request_;
+  std::unique_ptr<net::HttpRequestInfo> custom_request_;
 
   // Real network transaction.
-  scoped_ptr<net::HttpTransaction> network_transaction_;
+  std::unique_ptr<net::HttpTransaction> network_transaction_;
 
   const net::HttpRequestInfo* request_;
 
diff --git a/chrome/browser/devtools/devtools_network_transaction_factory.cc b/chrome/browser/devtools/devtools_network_transaction_factory.cc
index 323d7984..0b71ab2 100644
--- a/chrome/browser/devtools/devtools_network_transaction_factory.cc
+++ b/chrome/browser/devtools/devtools_network_transaction_factory.cc
@@ -31,8 +31,8 @@
 
 int DevToolsNetworkTransactionFactory::CreateTransaction(
     net::RequestPriority priority,
-    scoped_ptr<net::HttpTransaction>* trans) {
-  scoped_ptr<net::HttpTransaction> network_transaction;
+    std::unique_ptr<net::HttpTransaction>* trans) {
+  std::unique_ptr<net::HttpTransaction> network_transaction;
   int rv = network_layer_->CreateTransaction(priority, &network_transaction);
   if (rv != net::OK) {
     return rv;
diff --git a/chrome/browser/devtools/devtools_network_transaction_factory.h b/chrome/browser/devtools/devtools_network_transaction_factory.h
index 9fbbfef..c53d6fb4 100644
--- a/chrome/browser/devtools/devtools_network_transaction_factory.h
+++ b/chrome/browser/devtools/devtools_network_transaction_factory.h
@@ -5,8 +5,9 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_NETWORK_TRANSACTION_FACTORY_H_
 
+#include <memory>
+
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "net/base/request_priority.h"
 #include "net/http/http_transaction_factory.h"
 
@@ -28,13 +29,13 @@
 
   // net::HttpTransactionFactory methods:
   int CreateTransaction(net::RequestPriority priority,
-                        scoped_ptr<net::HttpTransaction>* trans) override;
+                        std::unique_ptr<net::HttpTransaction>* trans) override;
   net::HttpCache* GetCache() override;
   net::HttpNetworkSession* GetSession() override;
 
  private:
   DevToolsNetworkController* controller_;
-  scoped_ptr<net::HttpTransactionFactory> network_layer_;
+  std::unique_ptr<net::HttpTransactionFactory> network_layer_;
 
   DISALLOW_COPY_AND_ASSIGN(DevToolsNetworkTransactionFactory);
 };
diff --git a/chrome/browser/devtools/devtools_protocol.cc b/chrome/browser/devtools/devtools_protocol.cc
index 34e99b48..34bc3b6 100644
--- a/chrome/browser/devtools/devtools_protocol.cc
+++ b/chrome/browser/devtools/devtools_protocol.cc
@@ -29,7 +29,7 @@
 std::string DevToolsProtocol::SerializeCommand(
     int command_id,
     const std::string& method,
-    scoped_ptr<base::DictionaryValue> params) {
+    std::unique_ptr<base::DictionaryValue> params) {
   base::DictionaryValue command;
   command.SetInteger(kIdParam, command_id);
   command.SetString(kMethodParam, method);
@@ -42,10 +42,10 @@
 }
 
 // static
-scoped_ptr<base::DictionaryValue>
+std::unique_ptr<base::DictionaryValue>
 DevToolsProtocol::CreateInvalidParamsResponse(int command_id,
                                               const std::string& param) {
-  scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
+  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
   base::DictionaryValue* error_object = new base::DictionaryValue();
   response->Set(kErrorParam, error_object);
   error_object->SetInteger(kErrorCodeParam, kErrorInvalidParams);
@@ -56,11 +56,10 @@
 }
 
 // static
-scoped_ptr<base::DictionaryValue>
-DevToolsProtocol::CreateSuccessResponse(
+std::unique_ptr<base::DictionaryValue> DevToolsProtocol::CreateSuccessResponse(
     int command_id,
-    scoped_ptr<base::DictionaryValue> result) {
-  scoped_ptr<base::DictionaryValue> response(new base::DictionaryValue());
+    std::unique_ptr<base::DictionaryValue> result) {
+  std::unique_ptr<base::DictionaryValue> response(new base::DictionaryValue());
   response->SetInteger(kIdParam, command_id);
   response->Set(kResultParam,
                 result ? result.release() : new base::DictionaryValue());
@@ -92,18 +91,18 @@
 bool DevToolsProtocol::ParseNotification(
     const std::string& json,
     std::string* method,
-    scoped_ptr<base::DictionaryValue>* params) {
-  scoped_ptr<base::Value> value = base::JSONReader::Read(json);
+    std::unique_ptr<base::DictionaryValue>* params) {
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
   if (!value || !value->IsType(base::Value::TYPE_DICTIONARY))
     return false;
 
-  scoped_ptr<base::DictionaryValue> dict(
+  std::unique_ptr<base::DictionaryValue> dict(
       static_cast<base::DictionaryValue*>(value.release()));
 
   if (!dict->GetString(kMethodParam, method))
     return false;
 
-  scoped_ptr<base::Value> params_value;
+  std::unique_ptr<base::Value> params_value;
   dict->Remove(kParamsParam, &params_value);
   if (params_value && params_value->IsType(base::Value::TYPE_DICTIONARY))
     params->reset(static_cast<base::DictionaryValue*>(params_value.release()));
@@ -115,11 +114,11 @@
 bool DevToolsProtocol::ParseResponse(const std::string& json,
                                      int* command_id,
                                      int* error_code) {
-  scoped_ptr<base::Value> value = base::JSONReader::Read(json);
+  std::unique_ptr<base::Value> value = base::JSONReader::Read(json);
   if (!value || !value->IsType(base::Value::TYPE_DICTIONARY))
     return false;
 
-  scoped_ptr<base::DictionaryValue> dict(
+  std::unique_ptr<base::DictionaryValue> dict(
       static_cast<base::DictionaryValue*>(value.release()));
 
   if (!dict->GetInteger(kIdParam, command_id))
diff --git a/chrome/browser/devtools/devtools_protocol.h b/chrome/browser/devtools/devtools_protocol.h
index 41c7e9f..be1c5e3 100644
--- a/chrome/browser/devtools/devtools_protocol.h
+++ b/chrome/browser/devtools/devtools_protocol.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_PROTOCOL_H_
 
+#include <memory>
 #include <string>
 
 #include "base/compiler_specific.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/values.h"
 
 // Utility class for processing DevTools remote debugging messages.
@@ -22,21 +22,22 @@
 
   static bool ParseNotification(const std::string& json,
                                 std::string* method,
-                                scoped_ptr<base::DictionaryValue>* params);
+                                std::unique_ptr<base::DictionaryValue>* params);
 
   static bool ParseResponse(const std::string& json,
                             int* command_id,
                             int* error_code);
 
-  static std::string SerializeCommand(int command_id,
-                                      const std::string& method,
-                                      scoped_ptr<base::DictionaryValue> params);
-
-  static scoped_ptr<base::DictionaryValue> CreateSuccessResponse(
+  static std::string SerializeCommand(
       int command_id,
-      scoped_ptr<base::DictionaryValue> result);
+      const std::string& method,
+      std::unique_ptr<base::DictionaryValue> params);
 
-  static scoped_ptr<base::DictionaryValue> CreateInvalidParamsResponse(
+  static std::unique_ptr<base::DictionaryValue> CreateSuccessResponse(
+      int command_id,
+      std::unique_ptr<base::DictionaryValue> result);
+
+  static std::unique_ptr<base::DictionaryValue> CreateInvalidParamsResponse(
       int command_id,
       const std::string& param);
 
diff --git a/chrome/browser/devtools/devtools_sanity_browsertest.cc b/chrome/browser/devtools/devtools_sanity_browsertest.cc
index 2613d68..5144111 100644
--- a/chrome/browser/devtools/devtools_sanity_browsertest.cc
+++ b/chrome/browser/devtools/devtools_sanity_browsertest.cc
@@ -811,7 +811,7 @@
   // Our extension must load an URL from the test server, whose port is only
   // known at runtime. So, to embed the URL, we must dynamically generate the
   // extension, rather than loading it from static content.
-  scoped_ptr<extensions::TestExtensionDir> dir(
+  std::unique_ptr<extensions::TestExtensionDir> dir(
       new extensions::TestExtensionDir());
 
   extensions::DictionaryBuilder manifest;
@@ -1031,7 +1031,7 @@
     observer_.reset(new DevToolsWindowCreationObserver());
   }
  protected:
-  scoped_ptr<DevToolsWindowCreationObserver> observer_;
+  std::unique_ptr<DevToolsWindowCreationObserver> observer_;
 };
 
 IN_PROC_BROWSER_TEST_F(DevToolsAutoOpenerTest, TestAutoOpenForTabs) {
diff --git a/chrome/browser/devtools/devtools_target_impl.cc b/chrome/browser/devtools/devtools_target_impl.cc
index 9d5cac5..13d0911 100644
--- a/chrome/browser/devtools/devtools_target_impl.cc
+++ b/chrome/browser/devtools/devtools_target_impl.cc
@@ -199,7 +199,7 @@
 }
 
 // static
-scoped_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForTab(
+std::unique_ptr<DevToolsTargetImpl> DevToolsTargetImpl::CreateForTab(
     content::WebContents* web_contents) {
   // TODO(dgozman): these checks should not be necessary. See
   // http://crbug.com/489664.
@@ -207,7 +207,7 @@
     return nullptr;
   if (!DevToolsAgentHost::GetOrCreateFor(web_contents))
     return nullptr;
-  return scoped_ptr<DevToolsTargetImpl>(
+  return std::unique_ptr<DevToolsTargetImpl>(
       new WebContentsTarget(web_contents, true));
 }
 
diff --git a/chrome/browser/devtools/devtools_target_impl.h b/chrome/browser/devtools/devtools_target_impl.h
index 6b93fbb..984a0aa 100644
--- a/chrome/browser/devtools/devtools_target_impl.h
+++ b/chrome/browser/devtools/devtools_target_impl.h
@@ -5,10 +5,10 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TARGET_IMPL_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TARGET_IMPL_H_
 
+#include <memory>
 #include <vector>
 
 #include "base/callback.h"
-#include "base/memory/scoped_ptr.h"
 #include "components/devtools_discovery/basic_target_descriptor.h"
 
 class Profile;
@@ -51,7 +51,7 @@
   virtual void Reload() const;
 
   // Creates a new target associated with tab.
-  static scoped_ptr<DevToolsTargetImpl> CreateForTab(
+  static std::unique_ptr<DevToolsTargetImpl> CreateForTab(
       content::WebContents* web_contents);
 
   // Caller takes ownership of returned objects.
diff --git a/chrome/browser/devtools/devtools_targets_ui.cc b/chrome/browser/devtools/devtools_targets_ui.cc
index 3808103..d84cbe9 100644
--- a/chrome/browser/devtools/devtools_targets_ui.cc
+++ b/chrome/browser/devtools/devtools_targets_ui.cc
@@ -174,7 +174,7 @@
   void SendTargets(const std::vector<DevToolsTargetImpl*>& targets);
 
   content::NotificationRegistrar notification_registrar_;
-  scoped_ptr<CancelableTimer> timer_;
+  std::unique_ptr<CancelableTimer> timer_;
   scoped_refptr<WorkerObserver> observer_;
   base::WeakPtrFactory<LocalTargetsUIHandler> weak_factory_;
 };
@@ -401,18 +401,19 @@
 }
 
 // static
-scoped_ptr<DevToolsTargetsUIHandler>
+std::unique_ptr<DevToolsTargetsUIHandler>
 DevToolsTargetsUIHandler::CreateForLocal(
     const DevToolsTargetsUIHandler::Callback& callback) {
-  return scoped_ptr<DevToolsTargetsUIHandler>(
+  return std::unique_ptr<DevToolsTargetsUIHandler>(
       new LocalTargetsUIHandler(callback));
 }
 
 // static
-scoped_ptr<DevToolsTargetsUIHandler>
+std::unique_ptr<DevToolsTargetsUIHandler>
 DevToolsTargetsUIHandler::CreateForAdb(
-    const DevToolsTargetsUIHandler::Callback& callback, Profile* profile) {
-  return scoped_ptr<DevToolsTargetsUIHandler>(
+    const DevToolsTargetsUIHandler::Callback& callback,
+    Profile* profile) {
+  return std::unique_ptr<DevToolsTargetsUIHandler>(
       new AdbTargetsUIHandler(callback, profile));
 }
 
diff --git a/chrome/browser/devtools/devtools_targets_ui.h b/chrome/browser/devtools/devtools_targets_ui.h
index 9205576..43778a3 100644
--- a/chrome/browser/devtools/devtools_targets_ui.h
+++ b/chrome/browser/devtools/devtools_targets_ui.h
@@ -6,11 +6,11 @@
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TARGETS_UI_H_
 
 #include <map>
+#include <memory>
 #include <string>
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
 
 namespace base {
@@ -32,11 +32,12 @@
 
   std::string source_id() const { return source_id_; }
 
-  static scoped_ptr<DevToolsTargetsUIHandler> CreateForLocal(
+  static std::unique_ptr<DevToolsTargetsUIHandler> CreateForLocal(
       const Callback& callback);
 
-  static scoped_ptr<DevToolsTargetsUIHandler> CreateForAdb(
-      const Callback& callback, Profile* profile);
+  static std::unique_ptr<DevToolsTargetsUIHandler> CreateForAdb(
+      const Callback& callback,
+      Profile* profile);
 
   DevToolsTargetImpl* GetTarget(const std::string& target_id);
 
diff --git a/chrome/browser/devtools/devtools_toggle_action.h b/chrome/browser/devtools/devtools_toggle_action.h
index ecd8126..bda17074 100644
--- a/chrome/browser/devtools/devtools_toggle_action.h
+++ b/chrome/browser/devtools/devtools_toggle_action.h
@@ -7,7 +7,8 @@
 
 #include <stddef.h>
 
-#include "base/memory/scoped_ptr.h"
+#include <memory>
+
 #include "base/strings/string16.h"
 
 struct DevToolsToggleAction {
@@ -58,7 +59,7 @@
   Type type_;
 
   // Additional parameters for the Reveal action; NULL if of any other type.
-  scoped_ptr<RevealParams> params_;
+  std::unique_ptr<RevealParams> params_;
 };
 
 #endif  // CHROME_BROWSER_DEVTOOLS_DEVTOOLS_TOGGLE_ACTION_H_
diff --git a/chrome/browser/devtools/devtools_ui_bindings.cc b/chrome/browser/devtools/devtools_ui_bindings.cc
index 08231a5..470220f 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.cc
+++ b/chrome/browser/devtools/devtools_ui_bindings.cc
@@ -441,7 +441,7 @@
   base::ListValue* params = &empty_params;
 
   base::DictionaryValue* dict = NULL;
-  scoped_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
   if (!parsed_message ||
       !parsed_message->GetAsDictionary(&dict) ||
       !dict->GetString(kFrontendHostMethod, &method) ||
@@ -549,8 +549,9 @@
   pending_requests_[fetcher] = callback;
   fetcher->SetRequestContext(profile_->GetRequestContext());
   fetcher->SetExtraRequestHeaders(headers);
-  fetcher->SaveResponseWithWriter(scoped_ptr<net::URLFetcherResponseWriter>(
-      new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
+  fetcher->SaveResponseWithWriter(
+      std::unique_ptr<net::URLFetcherResponseWriter>(
+          new ResponseWriter(weak_factory_.GetWeakPtr(), stream_id)));
   fetcher->Start();
 }
 
@@ -685,7 +686,7 @@
     bool port_forwarding_enabled,
     const std::string& port_forwarding_config) {
   base::DictionaryValue* config_dict = nullptr;
-  scoped_ptr<base::Value> parsed_config =
+  std::unique_ptr<base::Value> parsed_config =
       base::JSONReader::Read(port_forwarding_config);
   if (!parsed_config || !parsed_config->GetAsDictionary(&config_dict))
     return;
@@ -902,7 +903,7 @@
 
 void DevToolsUIBindings::FileSystemAdded(
     const DevToolsFileHelper::FileSystem& file_system) {
-  scoped_ptr<base::DictionaryValue> file_system_value(
+  std::unique_ptr<base::DictionaryValue> file_system_value(
       CreateFileSystemValue(file_system));
   CallClientFunction("DevToolsAPI.fileSystemAdded",
                      file_system_value.get(), NULL, NULL);
@@ -981,7 +982,7 @@
     callback.Run(false);
     return;
   }
-  scoped_ptr<DevToolsConfirmInfoBarDelegate> delegate(
+  std::unique_ptr<DevToolsConfirmInfoBarDelegate> delegate(
       new DevToolsConfirmInfoBarDelegate(callback, message));
   GlobalConfirmInfoBar::Show(std::move(delegate));
 }
diff --git a/chrome/browser/devtools/devtools_ui_bindings.h b/chrome/browser/devtools/devtools_ui_bindings.h
index 371655b..06fab89 100644
--- a/chrome/browser/devtools/devtools_ui_bindings.h
+++ b/chrome/browser/devtools/devtools_ui_bindings.h
@@ -5,11 +5,11 @@
 #ifndef CHROME_BROWSER_DEVTOOLS_DEVTOOLS_UI_BINDINGS_H_
 #define CHROME_BROWSER_DEVTOOLS_DEVTOOLS_UI_BINDINGS_H_
 
+#include <memory>
 #include <string>
 #include <vector>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/devtools/device/devtools_android_bridge.h"
@@ -199,15 +199,15 @@
   void AddDevToolsExtensionsToClient();
 
   class FrontendWebContentsObserver;
-  scoped_ptr<FrontendWebContentsObserver> frontend_contents_observer_;
+  std::unique_ptr<FrontendWebContentsObserver> frontend_contents_observer_;
 
   Profile* profile_;
   DevToolsAndroidBridge* android_bridge_;
   content::WebContents* web_contents_;
-  scoped_ptr<Delegate> delegate_;
+  std::unique_ptr<Delegate> delegate_;
   scoped_refptr<content::DevToolsAgentHost> agent_host_;
-  scoped_ptr<content::DevToolsFrontendHost> frontend_host_;
-  scoped_ptr<DevToolsFileHelper> file_helper_;
+  std::unique_ptr<content::DevToolsFrontendHost> frontend_host_;
+  std::unique_ptr<DevToolsFileHelper> file_helper_;
   scoped_refptr<DevToolsFileSystemIndexer> file_system_indexer_;
   typedef std::map<
       int,
@@ -218,10 +218,11 @@
   bool devices_updates_enabled_;
   bool frontend_loaded_;
   bool reattaching_;
-  scoped_ptr<DevToolsTargetsUIHandler> remote_targets_handler_;
-  scoped_ptr<PortForwardingStatusSerializer> port_status_serializer_;
+  std::unique_ptr<DevToolsTargetsUIHandler> remote_targets_handler_;
+  std::unique_ptr<PortForwardingStatusSerializer> port_status_serializer_;
   PrefChangeRegistrar pref_change_registrar_;
-  scoped_ptr<DevToolsEmbedderMessageDispatcher> embedder_message_dispatcher_;
+  std::unique_ptr<DevToolsEmbedderMessageDispatcher>
+      embedder_message_dispatcher_;
   GURL url_;
   using PendingRequestsMap = std::map<const net::URLFetcher*, DispatchCallback>;
   PendingRequestsMap pending_requests_;
diff --git a/chrome/browser/devtools/devtools_window.cc b/chrome/browser/devtools/devtools_window.cc
index b81e049..1a0e12a 100644
--- a/chrome/browser/devtools/devtools_window.cc
+++ b/chrome/browser/devtools/devtools_window.cc
@@ -221,7 +221,7 @@
 
 void DevToolsEventForwarder::SetWhitelistedShortcuts(
     const std::string& message) {
-  scoped_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
+  std::unique_ptr<base::Value> parsed_message = base::JSONReader::Read(message);
   base::ListValue* shortcut_list;
   if (!parsed_message->GetAsList(&shortcut_list))
       return;
@@ -788,7 +788,7 @@
                           shared_worker_frontend,
                           remote_frontend,
                           can_dock, settings));
-  scoped_ptr<WebContents> main_web_contents(
+  std::unique_ptr<WebContents> main_web_contents(
       WebContents::Create(WebContents::CreateParams(profile)));
   main_web_contents->GetController().LoadURL(
       DecorateFrontendURL(url), content::Referrer(),
diff --git a/chrome/browser/devtools/devtools_window.h b/chrome/browser/devtools/devtools_window.h
index 63314397..1aeab13 100644
--- a/chrome/browser/devtools/devtools_window.h
+++ b/chrome/browser/devtools/devtools_window.h
@@ -322,7 +322,7 @@
   void UpdateBrowserToolbar();
   void UpdateBrowserWindow();
 
-  scoped_ptr<ObserverWithAccessor> inspected_contents_observer_;
+  std::unique_ptr<ObserverWithAccessor> inspected_contents_observer_;
 
   Profile* profile_;
   content::WebContents* main_web_contents_;
@@ -343,7 +343,7 @@
   base::Closure ready_for_test_callback_;
 
   base::TimeTicks inspect_element_start_time_;
-  scoped_ptr<DevToolsEventForwarder> event_forwarder_;
+  std::unique_ptr<DevToolsEventForwarder> event_forwarder_;
 
   friend class DevToolsEventForwarder;
   DISALLOW_COPY_AND_ASSIGN(DevToolsWindow);
diff --git a/chrome/browser/devtools/global_confirm_info_bar.cc b/chrome/browser/devtools/global_confirm_info_bar.cc
index eb4c945..d25d08e9 100644
--- a/chrome/browser/devtools/global_confirm_info_bar.cc
+++ b/chrome/browser/devtools/global_confirm_info_bar.cc
@@ -131,7 +131,7 @@
 
 // static
 base::WeakPtr<GlobalConfirmInfoBar> GlobalConfirmInfoBar::Show(
-    scoped_ptr<ConfirmInfoBarDelegate> delegate) {
+    std::unique_ptr<ConfirmInfoBarDelegate> delegate) {
   GlobalConfirmInfoBar* info_bar =
       new GlobalConfirmInfoBar(std::move(delegate));
   return info_bar->weak_factory_.GetWeakPtr();
@@ -142,12 +142,12 @@
 }
 
 GlobalConfirmInfoBar::GlobalConfirmInfoBar(
-    scoped_ptr<ConfirmInfoBarDelegate> delegate)
+    std::unique_ptr<ConfirmInfoBarDelegate> delegate)
     : delegate_(std::move(delegate)),
       browser_tab_strip_tracker_(this, nullptr, nullptr),
       weak_factory_(this) {
-   browser_tab_strip_tracker_.Init(
-       BrowserTabStripTracker::InitWith::BROWSERS_IN_ACTIVE_DESKTOP);
+  browser_tab_strip_tracker_.Init(
+      BrowserTabStripTracker::InitWith::BROWSERS_IN_ACTIVE_DESKTOP);
 }
 
 GlobalConfirmInfoBar::~GlobalConfirmInfoBar() {
@@ -170,7 +170,7 @@
   if (proxies_.find(infobar_service) != proxies_.end())
       return;
 
-  scoped_ptr<GlobalConfirmInfoBar::DelegateProxy> proxy(
+  std::unique_ptr<GlobalConfirmInfoBar::DelegateProxy> proxy(
       new GlobalConfirmInfoBar::DelegateProxy(weak_factory_.GetWeakPtr()));
   GlobalConfirmInfoBar::DelegateProxy* proxy_ptr = proxy.get();
   infobars::InfoBar* added_bar = infobar_service->AddInfoBar(
diff --git a/chrome/browser/devtools/global_confirm_info_bar.h b/chrome/browser/devtools/global_confirm_info_bar.h
index 1814b615..c7b562b 100644
--- a/chrome/browser/devtools/global_confirm_info_bar.h
+++ b/chrome/browser/devtools/global_confirm_info_bar.h
@@ -25,12 +25,13 @@
 class GlobalConfirmInfoBar : public TabStripModelObserver,
                              public infobars::InfoBarManager::Observer {
  public:
-  static base::WeakPtr<GlobalConfirmInfoBar>
-      Show(scoped_ptr<ConfirmInfoBarDelegate> delegate);
+  static base::WeakPtr<GlobalConfirmInfoBar> Show(
+      std::unique_ptr<ConfirmInfoBarDelegate> delegate);
   void Close();
 
  private:
-  explicit GlobalConfirmInfoBar(scoped_ptr<ConfirmInfoBarDelegate> delegate);
+  explicit GlobalConfirmInfoBar(
+      std::unique_ptr<ConfirmInfoBarDelegate> delegate);
   ~GlobalConfirmInfoBar() override;
   class DelegateProxy;
 
@@ -46,7 +47,7 @@
   void OnInfoBarRemoved(infobars::InfoBar* info_bar, bool animate) override;
   void OnManagerShuttingDown(infobars::InfoBarManager* manager) override;
 
-  scoped_ptr<ConfirmInfoBarDelegate> delegate_;
+  std::unique_ptr<ConfirmInfoBarDelegate> delegate_;
   std::map<infobars::InfoBarManager*, DelegateProxy*> proxies_;
   BrowserTabStripTracker browser_tab_strip_tracker_;
 
diff --git a/chrome/browser/devtools/remote_debugging_server.cc b/chrome/browser/devtools/remote_debugging_server.cc
index 2576410..cf2750f27 100644
--- a/chrome/browser/devtools/remote_debugging_server.cc
+++ b/chrome/browser/devtools/remote_debugging_server.cc
@@ -8,6 +8,7 @@
 
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/path_service.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
@@ -45,31 +46,32 @@
         last_tethering_port_(kMinTetheringPort) {}
 
  private:
-  scoped_ptr<net::ServerSocket> CreateLocalHostServerSocket(int port) {
-    scoped_ptr<net::ServerSocket> socket(
+  std::unique_ptr<net::ServerSocket> CreateLocalHostServerSocket(int port) {
+    std::unique_ptr<net::ServerSocket> socket(
         new net::TCPServerSocket(nullptr, net::NetLog::Source()));
     if (socket->ListenWithAddressAndPort(
             "127.0.0.1", port, kBackLog) == net::OK)
       return socket;
     if (socket->ListenWithAddressAndPort("::1", port, kBackLog) == net::OK)
       return socket;
-    return scoped_ptr<net::ServerSocket>();
+    return std::unique_ptr<net::ServerSocket>();
   }
 
   // devtools_http_handler::DevToolsHttpHandler::ServerSocketFactory.
-  scoped_ptr<net::ServerSocket> CreateForHttpServer() override {
-    scoped_ptr<net::ServerSocket> socket(
+  std::unique_ptr<net::ServerSocket> CreateForHttpServer() override {
+    std::unique_ptr<net::ServerSocket> socket(
         new net::TCPServerSocket(nullptr, net::NetLog::Source()));
     if (address_.empty())
       return CreateLocalHostServerSocket(port_);
     if (socket->ListenWithAddressAndPort(address_, port_, kBackLog) == net::OK)
       return socket;
-    return scoped_ptr<net::ServerSocket>();
+    return std::unique_ptr<net::ServerSocket>();
   }
 
-  scoped_ptr<net::ServerSocket> CreateForTethering(std::string* name) override {
+  std::unique_ptr<net::ServerSocket> CreateForTethering(
+      std::string* name) override {
     if (!g_tethering_enabled.Get())
-      return scoped_ptr<net::ServerSocket>();
+      return std::unique_ptr<net::ServerSocket>();
 
     if (last_tethering_port_ == kMaxTetheringPort)
       last_tethering_port_ = kMinTetheringPort;
@@ -176,13 +178,9 @@
 #endif
 
   devtools_http_handler_.reset(new devtools_http_handler::DevToolsHttpHandler(
-      make_scoped_ptr(new TCPServerSocketFactory(ip, port)),
-      std::string(),
-      new ChromeDevToolsHttpHandlerDelegate(),
-      output_dir,
-      debug_frontend_dir,
-      version_info::GetProductNameAndVersionForUserAgent(),
-      ::GetUserAgent()));
+      base::WrapUnique(new TCPServerSocketFactory(ip, port)), std::string(),
+      new ChromeDevToolsHttpHandlerDelegate(), output_dir, debug_frontend_dir,
+      version_info::GetProductNameAndVersionForUserAgent(), ::GetUserAgent()));
 }
 
 RemoteDebuggingServer::~RemoteDebuggingServer() {
diff --git a/chrome/browser/devtools/remote_debugging_server.h b/chrome/browser/devtools/remote_debugging_server.h
index 6394582..13cda19 100644
--- a/chrome/browser/devtools/remote_debugging_server.h
+++ b/chrome/browser/devtools/remote_debugging_server.h
@@ -7,10 +7,10 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 
 #include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
 
 namespace devtools_http_handler {
 class DevToolsHttpHandler;
@@ -27,7 +27,8 @@
   virtual ~RemoteDebuggingServer();
 
  private:
-  scoped_ptr<devtools_http_handler::DevToolsHttpHandler> devtools_http_handler_;
+  std::unique_ptr<devtools_http_handler::DevToolsHttpHandler>
+      devtools_http_handler_;
   DISALLOW_COPY_AND_ASSIGN(RemoteDebuggingServer);
 };
 
diff --git a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
index d3e21f8..04db0eb 100644
--- a/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate_unittest.cc
@@ -490,8 +490,7 @@
 class TestDownloadProtectionService
     : public safe_browsing::DownloadProtectionService {
  public:
-  TestDownloadProtectionService()
-      : DownloadProtectionService(nullptr, nullptr) {}
+  TestDownloadProtectionService() : DownloadProtectionService(nullptr) {}
 
   void CheckClientDownload(DownloadItem* download_item,
                            const CheckDownloadCallback& callback) override {
diff --git a/chrome/browser/download/download_browsertest.cc b/chrome/browser/download/download_browsertest.cc
index c9401185..dd3987c7 100644
--- a/chrome/browser/download/download_browsertest.cc
+++ b/chrome/browser/download/download_browsertest.cc
@@ -1079,7 +1079,7 @@
     : public safe_browsing::DownloadProtectionService {
  public:
   FakeDownloadProtectionService()
-      : safe_browsing::DownloadProtectionService(nullptr, nullptr) {}
+      : safe_browsing::DownloadProtectionService(nullptr) {}
 
   void CheckClientDownload(DownloadItem* download_item,
       const CheckDownloadCallback& callback) override {
@@ -1088,13 +1088,13 @@
   }
 };
 
-class FakeSafeBrowsingService : public safe_browsing::SafeBrowsingService {
+class FakeSafeBrowsingService
+    : public safe_browsing::SafeBrowsingService,
+      public safe_browsing::ServicesDelegate::ServicesCreator {
  public:
-  FakeSafeBrowsingService() {}
-
-  safe_browsing::DownloadProtectionService* CreateDownloadProtectionService(
-      net::URLRequestContextGetter* not_used_request_context_getter) override {
-    return new FakeDownloadProtectionService();
+  FakeSafeBrowsingService() {
+    services_delegate_ =
+        safe_browsing::ServicesDelegate::CreateForTest(this, this);
   }
 
   std::string GetDownloadReport() const { return report_; }
@@ -1102,11 +1102,33 @@
  protected:
   ~FakeSafeBrowsingService() override {}
 
+  // ServicesDelegate::ServicesCreator:
+  bool CanCreateDownloadProtectionService() override { return true; }
+  bool CanCreateIncidentReportingService() override { return false; }
+  bool CanCreateResourceRequestDetector() override { return false; }
+  safe_browsing::DownloadProtectionService* CreateDownloadProtectionService()
+      override {
+    return new FakeDownloadProtectionService();
+  }
+  safe_browsing::IncidentReportingService* CreateIncidentReportingService()
+      override {
+    NOTREACHED();
+    return nullptr;
+  }
+  safe_browsing::ResourceRequestDetector* CreateResourceRequestDetector()
+      override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  // SafeBrowsingService:
   void SendSerializedDownloadReport(const std::string& report) override {
     report_ = report;
   }
 
   std::string report_;
+
+  DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
 };
 
 // Factory that creates FakeSafeBrowsingService instances.
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api.cc b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
index cf3996c..8cef3353 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api.cc
@@ -402,21 +402,6 @@
   registrar_.RemoveAll();
 }
 
-void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {
-  if (!details.browser_context)
-    return;
-  InputImeEventRouter* event_router =
-      GetInputImeEventRouter(Profile::FromBrowserContext(
-          Profile::FromBrowserContext(details.browser_context)));
-  InputMethodEngineBase* engine =
-      event_router ? event_router->GetActiveEngine(details.extension_id)
-                   : nullptr;
-
-  // Notifies the IME extension for IME ready with onActivate/onFocus events.
-  if (engine)
-    engine->Enable(engine->GetActiveComponentId());
-}
-
 static base::LazyInstance<BrowserContextKeyedAPIFactory<InputImeAPI> >
     g_factory = LAZY_INSTANCE_INITIALIZER;
 
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
index 2b13b1d7..dc04808 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc
@@ -630,4 +630,15 @@
   }
 }
 
+void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {
+  if (!details.browser_context)
+    return;
+  InputMethodEngine* engine =
+      GetActiveEngine(Profile::FromBrowserContext(details.browser_context),
+                      details.extension_id);
+  // Notifies the IME extension for IME ready with onActivate/onFocus events.
+  if (engine)
+    engine->Enable(engine->GetActiveComponentId());
+}
+
 }  // namespace extensions
diff --git a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
index 87cf0a3..d8502707 100644
--- a/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
+++ b/chrome/browser/extensions/api/input_ime/input_ime_api_nonchromeos.cc
@@ -142,6 +142,8 @@
     event_router->DeleteInputMethodEngine(extension->id());
 }
 
+void InputImeAPI::OnListenerAdded(const EventListenerInfo& details) {}
+
 InputImeEventRouter::InputImeEventRouter(Profile* profile)
     : InputImeEventRouterBase(profile), active_engine_(nullptr) {}
 
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.cc b/chrome/browser/password_manager/chrome_password_manager_client.cc
index 9264179..0c11394 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client.cc
@@ -33,7 +33,6 @@
 #include "components/browser_sync/browser/profile_sync_service.h"
 #include "components/password_manager/content/browser/content_password_manager_driver.h"
 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
-#include "components/password_manager/content/common/credential_manager_messages.h"
 #include "components/password_manager/core/browser/browser_save_password_progress_logger.h"
 #include "components/password_manager/core/browser/log_manager.h"
 #include "components/password_manager/core/browser/log_receiver.h"
@@ -141,7 +140,7 @@
       profile_(Profile::FromBrowserContext(web_contents->GetBrowserContext())),
       password_manager_(this),
       driver_factory_(nullptr),
-      credential_manager_dispatcher_(web_contents, this),
+      credential_manager_impl_(web_contents, this),
       observer_(nullptr),
       credentials_filter_(this,
                           base::Bind(&GetSyncService, profile_),
@@ -611,3 +610,17 @@
     const {
   return log_manager_.get();
 }
+
+// static
+void ChromePasswordManagerClient::BindCredentialManager(
+    content::RenderFrameHost* render_frame_host,
+    password_manager::mojom::CredentialManagerRequest request) {
+  content::WebContents* web_contents =
+      content::WebContents::FromRenderFrameHost(render_frame_host);
+  DCHECK(web_contents);
+
+  ChromePasswordManagerClient* instance =
+      ChromePasswordManagerClient::FromWebContents(web_contents);
+  DCHECK(instance);
+  instance->credential_manager_impl_.BindRequest(std::move(request));
+}
diff --git a/chrome/browser/password_manager/chrome_password_manager_client.h b/chrome/browser/password_manager/chrome_password_manager_client.h
index fa85691..150d83acc 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client.h
+++ b/chrome/browser/password_manager/chrome_password_manager_client.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_vector.h"
 #include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
-#include "components/password_manager/content/browser/credential_manager_dispatcher.h"
+#include "components/password_manager/content/browser/credential_manager_impl.h"
 #include "components/password_manager/core/browser/password_manager.h"
 #include "components/password_manager/core/browser/password_manager_client.h"
 #include "components/password_manager/sync/browser/sync_credentials_filter.h"
@@ -105,6 +105,10 @@
   // the sad old Infobar UI.
   static bool IsTheHotNewBubbleUIEnabled();
 
+  static void BindCredentialManager(
+      content::RenderFrameHost* render_frame_host,
+      password_manager::mojom::CredentialManagerRequest request);
+
  protected:
   // Callable for tests.
   ChromePasswordManagerClient(content::WebContents* web_contents,
@@ -168,8 +172,10 @@
 
   password_manager::ContentPasswordManagerDriverFactory* driver_factory_;
 
-  password_manager::CredentialManagerDispatcher
-      credential_manager_dispatcher_;
+  // As a mojo service, will be registered into service registry
+  // of the main frame host by ChromeContentBrowserClient
+  // once main frame host was created.
+  password_manager::CredentialManagerImpl credential_manager_impl_;
 
   // Observer for password generation popup.
   autofill::PasswordGenerationPopupObserver* observer_;
diff --git a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
index 056525ff..588dc8d0 100644
--- a/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
+++ b/chrome/browser/password_manager/chrome_password_manager_client_unittest.cc
@@ -20,7 +20,6 @@
 #include "chrome/test/base/testing_profile.h"
 #include "components/autofill/content/common/autofill_messages.h"
 #include "components/password_manager/content/browser/password_manager_internals_service_factory.h"
-#include "components/password_manager/content/common/credential_manager_messages.h"
 #include "components/password_manager/core/browser/credentials_filter.h"
 #include "components/password_manager/core/browser/log_manager.h"
 #include "components/password_manager/core/browser/log_receiver.h"
diff --git a/chrome/browser/safe_browsing/download_protection_service.cc b/chrome/browser/safe_browsing/download_protection_service.cc
index 9f5afd49..48c798a5 100644
--- a/chrome/browser/safe_browsing/download_protection_service.cc
+++ b/chrome/browser/safe_browsing/download_protection_service.cc
@@ -1063,15 +1063,15 @@
 };
 
 DownloadProtectionService::DownloadProtectionService(
-    SafeBrowsingService* sb_service,
-    net::URLRequestContextGetter* request_context_getter)
-    : request_context_getter_(request_context_getter),
+    SafeBrowsingService* sb_service)
+    : request_context_getter_(sb_service ? sb_service->url_request_context()
+                                         : nullptr),
       enabled_(false),
       binary_feature_extractor_(new BinaryFeatureExtractor()),
       download_request_timeout_ms_(kDownloadRequestTimeoutMs),
-      feedback_service_(new DownloadFeedbackService(
-          request_context_getter, BrowserThread::GetBlockingPool())) {
-
+      feedback_service_(
+          new DownloadFeedbackService(request_context_getter_.get(),
+                                      BrowserThread::GetBlockingPool())) {
   if (sb_service) {
     ui_manager_ = sb_service->ui_manager();
     database_manager_ = sb_service->database_manager();
diff --git a/chrome/browser/safe_browsing/download_protection_service.h b/chrome/browser/safe_browsing/download_protection_service.h
index bba8f07..7cddf1f 100644
--- a/chrome/browser/safe_browsing/download_protection_service.h
+++ b/chrome/browser/safe_browsing/download_protection_service.h
@@ -74,11 +74,8 @@
       ClientDownloadRequestSubscription;
 
   // Creates a download service.  The service is initially disabled.  You need
-  // to call SetEnabled() to start it.  |sb_service| owns this object; we
-  // keep a reference to |request_context_getter|.
-  DownloadProtectionService(
-      SafeBrowsingService* sb_service,
-      net::URLRequestContextGetter* request_context_getter);
+  // to call SetEnabled() to start it.  |sb_service| owns this object.
+  explicit DownloadProtectionService(SafeBrowsingService* sb_service);
 
   virtual ~DownloadProtectionService();
 
diff --git a/chrome/browser/safe_browsing/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
index dd4f5458..9262f807 100644
--- a/chrome/browser/safe_browsing/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection_service_unittest.cc
@@ -88,9 +88,12 @@
   DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingDatabaseManager);
 };
 
-class FakeSafeBrowsingService : public SafeBrowsingService {
+class FakeSafeBrowsingService : public SafeBrowsingService,
+                                public ServicesDelegate::ServicesCreator {
  public:
-  FakeSafeBrowsingService() { }
+  FakeSafeBrowsingService() {
+    services_delegate_ = ServicesDelegate::CreateForTest(this, this);
+  }
 
   // Returned pointer has the same lifespan as the database_manager_ refcounted
   // object.
@@ -106,10 +109,6 @@
     return mock_database_manager_;
   }
 
-  IncidentReportingService* CreateIncidentReportingService() override {
-    return new IncidentReportingService(nullptr, nullptr);
-  }
-
   SafeBrowsingProtocolManagerDelegate* GetProtocolManagerDelegate() override {
     // Our SafeBrowsingDatabaseManager doesn't implement this delegate.
     return NULL;
@@ -118,6 +117,22 @@
   void RegisterAllDelayedAnalysis() override {}
 
  private:
+  // ServicesDelegate::ServicesCreator:
+  bool CanCreateDownloadProtectionService() override { return false; }
+  bool CanCreateIncidentReportingService() override { return true; }
+  bool CanCreateResourceRequestDetector() override { return false; }
+  DownloadProtectionService* CreateDownloadProtectionService() override {
+    NOTREACHED();
+    return nullptr;
+  }
+  IncidentReportingService* CreateIncidentReportingService() override {
+    return new IncidentReportingService(nullptr);
+  }
+  ResourceRequestDetector* CreateResourceRequestDetector() override {
+    NOTREACHED();
+    return nullptr;
+  }
+
   MockSafeBrowsingDatabaseManager* mock_database_manager_;
 
   DISALLOW_COPY_AND_ASSIGN(FakeSafeBrowsingService);
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
index c7b87be..ecd5aea 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.cc
@@ -328,12 +328,13 @@
 }
 
 IncidentReportingService::IncidentReportingService(
-    SafeBrowsingService* safe_browsing_service,
-    const scoped_refptr<net::URLRequestContextGetter>& request_context_getter)
+    SafeBrowsingService* safe_browsing_service)
     : database_manager_(safe_browsing_service
                             ? safe_browsing_service->database_manager()
-                            : NULL),
-      url_request_context_getter_(request_context_getter),
+                            : nullptr),
+      url_request_context_getter_(
+          safe_browsing_service ? safe_browsing_service->url_request_context()
+                                : nullptr),
       collect_environment_data_fn_(&CollectEnvironmentData),
       environment_collection_task_runner_(
           content::BrowserThread::GetBlockingPool()
diff --git a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
index fb5dc0e..c692814 100644
--- a/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
+++ b/chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h
@@ -76,10 +76,7 @@
 // remaining are uploaded in an incident report.
 class IncidentReportingService : public content::NotificationObserver {
  public:
-  IncidentReportingService(
-      SafeBrowsingService* safe_browsing_service,
-      const scoped_refptr<net::URLRequestContextGetter>&
-          request_context_getter);
+  explicit IncidentReportingService(SafeBrowsingService* safe_browsing_service);
 
   // All incident collection, data collection, and uploads in progress are
   // dropped at destruction.
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
index cef4dec..521be32 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.cc
@@ -120,6 +120,19 @@
 
 }  // namespace
 
+// static
+ResourceRequestInfo ResourceRequestDetector::GetRequestInfo(
+    const net::URLRequest* request) {
+  ResourceRequestInfo info;
+  info.url = request->url();
+  const content::ResourceRequestInfo* request_info =
+      content::ResourceRequestInfo::ForRequest(request);
+  info.resource_type = request_info->GetResourceType();
+  content::ResourceRequestInfo::GetRenderFrameForRequest(
+      request, &info.render_process_id, &info.render_frame_id);
+  return info;
+}
+
 ResourceRequestDetector::ResourceRequestDetector(
     scoped_refptr<SafeBrowsingDatabaseManager> database_manager,
     std::unique_ptr<IncidentReceiver> incident_receiver)
@@ -131,27 +144,20 @@
 ResourceRequestDetector::~ResourceRequestDetector() {
 }
 
-void ResourceRequestDetector::OnResourceRequest(
-    const net::URLRequest* request) {
+void ResourceRequestDetector::ProcessResourceRequest(
+    const ResourceRequestInfo* request) {
   // Only look at actual net requests (e.g., not chrome-extensions://id/foo.js).
-  if (!request->url().SchemeIsHTTPOrHTTPS())
+  if (!request->url.SchemeIsHTTPOrHTTPS())
     return;
 
-  const content::ResourceRequestInfo* request_info =
-      content::ResourceRequestInfo::ForRequest(request);
-  content::ResourceType resource_type = request_info->GetResourceType();
-  if (resource_type == content::RESOURCE_TYPE_SUB_FRAME ||
-      resource_type == content::RESOURCE_TYPE_SCRIPT ||
-      resource_type == content::RESOURCE_TYPE_OBJECT) {
-    int render_process_id = 0;
-    int render_frame_id = 0;
-    content::ResourceRequestInfo::GetRenderFrameForRequest(
-        request, &render_process_id, &render_frame_id);
+  if (request->resource_type == content::RESOURCE_TYPE_SUB_FRAME ||
+      request->resource_type == content::RESOURCE_TYPE_SCRIPT ||
+      request->resource_type == content::RESOURCE_TYPE_OBJECT) {
     new ResourceRequestDetectorClient(
-        request->url(), database_manager_,
+        request->url, database_manager_,
         base::Bind(&ResourceRequestDetector::ReportIncidentOnUIThread,
-                  weak_ptr_factory_.GetWeakPtr(), render_process_id,
-                  render_frame_id));
+                   weak_ptr_factory_.GetWeakPtr(), request->render_process_id,
+                   request->render_frame_id));
   }
 }
 
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
index bac5cb9..4140896 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h
@@ -23,9 +23,18 @@
 
 class ClientIncidentReport_IncidentData_ResourceRequestIncident;
 
+struct ResourceRequestInfo {
+  GURL url;
+  content::ResourceType resource_type;
+  int render_process_id;
+  int render_frame_id;
+};
+
 // Observes network requests and reports suspicious activity.
 class ResourceRequestDetector {
  public:
+  static ResourceRequestInfo GetRequestInfo(const net::URLRequest* request);
+
   ResourceRequestDetector(
       scoped_refptr<SafeBrowsingDatabaseManager> sb_database_manager,
       std::unique_ptr<IncidentReceiver> incident_receiver);
@@ -33,7 +42,7 @@
 
   // Analyzes the |request| and triggers an incident report on suspicious
   // script inclusion.
-  void OnResourceRequest(const net::URLRequest* request);
+  void ProcessResourceRequest(const ResourceRequestInfo* request);
 
  protected:
   // Testing hook.
diff --git a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
index dc30b51..838720be 100644
--- a/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
+++ b/chrome/browser/safe_browsing/incident_reporting/resource_request_detector_unittest.cc
@@ -132,7 +132,9 @@
     EXPECT_CALL(*mock_incident_receiver_, DoAddIncidentForProfile(IsNull(), _))
         .Times(0);
 
-    fake_resource_request_detector_.OnResourceRequest(request.get());
+    ResourceRequestInfo info =
+        ResourceRequestDetector::GetRequestInfo(request.get());
+    fake_resource_request_detector_.ProcessResourceRequest(&info);
     base::RunLoop().RunUntilIdle();
   }
 
@@ -147,7 +149,9 @@
     EXPECT_CALL(*mock_incident_receiver_, DoAddIncidentForProfile(IsNull(), _))
         .WillOnce(WithArg<1>(TakeIncident(&incident)));
 
-    fake_resource_request_detector_.OnResourceRequest(request.get());
+    ResourceRequestInfo info =
+        ResourceRequestDetector::GetRequestInfo(request.get());
+    fake_resource_request_detector_.ProcessResourceRequest(&info);
     base::RunLoop().RunUntilIdle();
 
     ASSERT_TRUE(incident);
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.cc b/chrome/browser/safe_browsing/safe_browsing_service.cc
index d0c76e08..a9e5bfc1 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service.cc
@@ -27,11 +27,7 @@
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/profiles/profile_manager.h"
-#include "chrome/browser/safe_browsing/client_side_detection_service.h"
-#include "chrome/browser/safe_browsing/download_protection_service.h"
 #include "chrome/browser/safe_browsing/ping_manager.h"
-#include "chrome/browser/safe_browsing/protocol_manager.h"
-#include "chrome/browser/safe_browsing/protocol_manager_helper.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
 #include "chrome/common/chrome_constants.h"
 #include "chrome/common/chrome_paths.h"
@@ -46,6 +42,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/cookie_store_factory.h"
 #include "content/public/browser/notification_service.h"
+#include "content/public/browser/resource_request_info.h"
 #include "google_apis/google_api_keys.h"
 #include "net/cookies/cookie_store.h"
 #include "net/extras/sqlite/cookie_crypto_delegate.h"
@@ -63,12 +60,16 @@
 #endif
 
 #if defined(FULL_SAFE_BROWSING)
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
+#include "chrome/browser/safe_browsing/download_protection_service.h"
 #include "chrome/browser/safe_browsing/incident_reporting/binary_integrity_analyzer.h"
 #include "chrome/browser/safe_browsing/incident_reporting/blacklist_load_analyzer.h"
 #include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
 #include "chrome/browser/safe_browsing/incident_reporting/module_load_analyzer.h"
 #include "chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h"
 #include "chrome/browser/safe_browsing/incident_reporting/variations_seed_signature_analyzer.h"
+#include "chrome/browser/safe_browsing/protocol_manager.h"
+#include "chrome/browser/safe_browsing/protocol_manager_helper.h"
 #endif
 
 using content::BrowserThread;
@@ -240,8 +241,9 @@
 }
 
 SafeBrowsingService::SafeBrowsingService()
-    : protocol_manager_(NULL),
-      ping_manager_(NULL),
+    : services_delegate_(ServicesDelegate::Create(this)),
+      protocol_manager_(nullptr),
+      ping_manager_(nullptr),
       enabled_(false),
       enabled_by_prefs_(false) {}
 
@@ -259,22 +261,8 @@
 
   database_manager_ = CreateDatabaseManager();
 
-#if defined(FULL_SAFE_BROWSING)
-#if defined(SAFE_BROWSING_CSD)
-  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kDisableClientSidePhishingDetection)) {
-    csd_service_.reset(ClientSideDetectionService::Create(
-        url_request_context_getter_.get()));
-  }
-#endif  // defined(SAFE_BROWSING_CSD)
-
-  download_service_.reset(CreateDownloadProtectionService(
-      url_request_context_getter_.get()));
-
-  incident_service_.reset(CreateIncidentReportingService());
-  resource_request_detector_.reset(new ResourceRequestDetector(
-      database_manager_, incident_service_->GetIncidentReceiver()));
-#endif  // !defined(FULL_SAFE_BROWSING)
+  services_delegate_->InitializeCsdService(url_request_context_getter_.get());
+  services_delegate_->InitializeServices();
 
   // Track the safe browsing preference of existing profiles.
   // The SafeBrowsingService will be started if any existing profile has the
@@ -298,10 +286,8 @@
   prefs_registrar_.Add(this, chrome::NOTIFICATION_PROFILE_DESTROYED,
                        content::NotificationService::AllSources());
 
-#if defined(FULL_SAFE_BROWSING)
   // Register all the delayed analysis to the incident reporting service.
   RegisterAllDelayedAnalysis();
-#endif
 }
 
 void SafeBrowsingService::ShutDown() {
@@ -313,17 +299,8 @@
   prefs_registrar_.RemoveAll();
 
   Stop(true);
-  // The IO thread is going away, so make sure the ClientSideDetectionService
-  // dtor executes now since it may call the dtor of URLFetcher which relies
-  // on it.
-  csd_service_.reset();
 
-#if defined(FULL_SAFE_BROWSING)
-  resource_request_detector_.reset();
-  incident_service_.reset();
-#endif
-
-  download_service_.reset();
+  services_delegate_->ShutdownServices();
 
   // Since URLRequestContextGetters are refcounted, can't count on clearing
   // |url_request_context_getter_| to delete it, so need to shut it down first,
@@ -383,39 +360,35 @@
 std::unique_ptr<TrackedPreferenceValidationDelegate>
 SafeBrowsingService::CreatePreferenceValidationDelegate(
     Profile* profile) const {
-#if defined(FULL_SAFE_BROWSING)
-  return incident_service_->CreatePreferenceValidationDelegate(profile);
-#else
-  return std::unique_ptr<TrackedPreferenceValidationDelegate>();
-#endif
+  return services_delegate_->CreatePreferenceValidationDelegate(profile);
 }
 
-#if defined(FULL_SAFE_BROWSING)
 void SafeBrowsingService::RegisterDelayedAnalysisCallback(
     const DelayedAnalysisCallback& callback) {
-  incident_service_->RegisterDelayedAnalysisCallback(callback);
+  services_delegate_->RegisterDelayedAnalysisCallback(callback);
 }
 
 void SafeBrowsingService::RegisterExtendedReportingOnlyDelayedAnalysisCallback(
     const DelayedAnalysisCallback& callback) {
-  incident_service_->RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+  services_delegate_->RegisterExtendedReportingOnlyDelayedAnalysisCallback(
       callback);
 }
-#endif
 
 void SafeBrowsingService::AddDownloadManager(
     content::DownloadManager* download_manager) {
-#if defined(FULL_SAFE_BROWSING)
-  incident_service_->AddDownloadManager(download_manager);
-#endif
+  services_delegate_->AddDownloadManager(download_manager);
 }
 
 void SafeBrowsingService::OnResourceRequest(const net::URLRequest* request) {
 #if defined(FULL_SAFE_BROWSING)
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
   TRACE_EVENT1("loader", "SafeBrowsingService::OnResourceRequest", "url",
                request->url().spec());
-  if (resource_request_detector_)
-    resource_request_detector_->OnResourceRequest(request);
+
+  ResourceRequestInfo info = ResourceRequestDetector::GetRequestInfo(request);
+  BrowserThread::PostTask(
+      BrowserThread::UI, FROM_HERE,
+      base::Bind(&SafeBrowsingService::ProcessResourceRequest, this, info));
 #endif
 }
 
@@ -433,27 +406,12 @@
 #endif
 }
 
-#if defined(FULL_SAFE_BROWSING)
-DownloadProtectionService* SafeBrowsingService::CreateDownloadProtectionService(
-      net::URLRequestContextGetter* request_context_getter) {
-  return new DownloadProtectionService(this, request_context_getter);
-}
-
-IncidentReportingService*
-SafeBrowsingService::CreateIncidentReportingService() {
-  return new IncidentReportingService(
-      this, url_request_context_getter_);
-}
-#endif
-
 void SafeBrowsingService::RegisterAllDelayedAnalysis() {
 #if defined(FULL_SAFE_BROWSING)
   RegisterBinaryIntegrityAnalysis();
   RegisterBlacklistLoadAnalysis();
   RegisterModuleLoadAnalysis(database_manager_);
   RegisterVariationsSeedSignatureAnalysis();
-#else
-  NOTREACHED();
 #endif
 }
 
@@ -563,13 +521,11 @@
     enabled_ = false;
 
 #if defined(SAFE_BROWSING_DB_LOCAL)
-    // This cancels all in-flight GetHash requests. Note that database_manager_
-    // relies on the protocol_manager_ so if the latter is destroyed, the
-    // former must be stopped.
-    if (protocol_manager_) {
-      delete protocol_manager_;
-      protocol_manager_ = NULL;
-    }
+    // This cancels all in-flight GetHash requests. Note that
+    // |database_manager_| relies on |protocol_manager_| so if the latter is
+    // destroyed, the former must be stopped.
+    delete protocol_manager_;
+    protocol_manager_ = nullptr;
 #endif
     delete ping_manager_;
     ping_manager_ = NULL;
@@ -675,12 +631,7 @@
 
   state_callback_list_.Notify();
 
-#if defined(FULL_SAFE_BROWSING)
-  if (csd_service_)
-    csd_service_->SetEnabledAndRefreshState(enable);
-  if (download_service_)
-    download_service_->SetEnabled(enable);
-#endif
+  services_delegate_->RefreshState(enable);
 }
 
 void SafeBrowsingService::SendSerializedDownloadReport(
@@ -699,4 +650,10 @@
     ping_manager()->ReportThreatDetails(report);
 }
 
+void SafeBrowsingService::ProcessResourceRequest(
+    const ResourceRequestInfo& request) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  services_delegate_->ProcessResourceRequest(&request);
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/safe_browsing_service.h b/chrome/browser/safe_browsing/safe_browsing_service.h
index 630e6292..f5de477 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service.h
+++ b/chrome/browser/safe_browsing/safe_browsing_service.h
@@ -19,6 +19,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/observer_list.h"
 #include "base/sequenced_task_runner_helpers.h"
+#include "chrome/browser/safe_browsing/services_delegate.h"
 #include "components/safe_browsing_db/util.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_observer.h"
@@ -33,16 +34,11 @@
 class Profile;
 class TrackedPreferenceValidationDelegate;
 
-namespace base {
-class Thread;
-}
-
 namespace content {
 class DownloadManager;
 }
 
 namespace net {
-class CookieStore;
 class URLRequest;
 class URLRequestContextGetter;
 }
@@ -50,6 +46,7 @@
 namespace safe_browsing {
 class ClientSideDetectionService;
 class DownloadProtectionService;
+struct ResourceRequestInfo;
 struct SafeBrowsingProtocolConfig;
 class SafeBrowsingDatabaseManager;
 class SafeBrowsingPingManager;
@@ -63,7 +60,6 @@
 #if defined(FULL_SAFE_BROWSING)
 class IncidentReportingService;
 class OffDomainInclusionDetector;
-class ResourceRequestDetector;
 #endif
 
 // Construction needs to happen on the main thread.
@@ -71,13 +67,11 @@
 // the heavylifting of safebrowsing service. Both of these managers stay
 // alive until SafeBrowsingService is destroyed, however, they are disabled
 // permanently when Shutdown method is called.
-class SafeBrowsingService
-    : public base::RefCountedThreadSafe<
-          SafeBrowsingService,
-          content::BrowserThread::DeleteOnUIThread>,
-      public content::NotificationObserver {
+class SafeBrowsingService : public base::RefCountedThreadSafe<
+                                SafeBrowsingService,
+                                content::BrowserThread::DeleteOnUIThread>,
+                            public content::NotificationObserver {
  public:
-
   // Makes the passed |factory| the factory used to instanciate
   // a SafeBrowsingService. Useful for tests.
   static void RegisterFactory(SafeBrowsingServiceFactory* factory) {
@@ -123,15 +117,13 @@
   }
 
   ClientSideDetectionService* safe_browsing_detection_service() const {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return csd_service_.get();
+    return services_delegate_->GetCsdService();
   }
 
   // The DownloadProtectionService is not valid after the SafeBrowsingService
   // is destroyed.
   DownloadProtectionService* download_protection_service() const {
-    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-    return download_service_.get();
+    return services_delegate_->GetDownloadService();
   }
 
   net::URLRequestContextGetter* url_request_context();
@@ -150,14 +142,12 @@
   std::unique_ptr<TrackedPreferenceValidationDelegate>
   CreatePreferenceValidationDelegate(Profile* profile) const;
 
-#if defined(FULL_SAFE_BROWSING)
   // Registers |callback| to be run after some delay following process launch.
   // |callback| will be dropped if the service is not applicable for the
   // process.
   void RegisterDelayedAnalysisCallback(const DelayedAnalysisCallback& callback);
   void RegisterExtendedReportingOnlyDelayedAnalysisCallback(
       const DelayedAnalysisCallback& callback);
-#endif
 
   // Adds |download_manager| to the set monitored by safe browsing.
   void AddDownloadManager(content::DownloadManager* download_manager);
@@ -188,13 +178,6 @@
 
   virtual SafeBrowsingUIManager* CreateUIManager();
 
-#if defined(FULL_SAFE_BROWSING)
-  virtual DownloadProtectionService* CreateDownloadProtectionService(
-      net::URLRequestContextGetter* request_context_getter);
-
-  virtual IncidentReportingService* CreateIncidentReportingService();
-#endif
-
   // Registers all the delayed analysis with the incident reporting service.
   // This is where you register your process-wide, profile-independent analysis.
   virtual void RegisterAllDelayedAnalysis();
@@ -202,6 +185,8 @@
   // Return a ptr to DatabaseManager's delegate, or NULL if it doesn't have one.
   virtual SafeBrowsingProtocolManagerDelegate* GetProtocolManagerDelegate();
 
+  std::unique_ptr<ServicesDelegate> services_delegate_;
+
  private:
   friend class SafeBrowsingServiceFactoryImpl;
   friend struct content::BrowserThread::DeleteOnThread<
@@ -249,6 +234,9 @@
 
   void OnSendSerializedDownloadReport(const std::string& report);
 
+  // Process the observed resource requests on the UI thread.
+  void ProcessResourceRequest(const ResourceRequestInfo& request);
+
   // The factory used to instanciate a SafeBrowsingService object.
   // Useful for tests, so they can provide their own implementation of
   // SafeBrowsingService.
@@ -286,20 +274,6 @@
   // Should only be accessed on the UI thread.
   base::CallbackList<void(void)> state_callback_list_;
 
-  // The ClientSideDetectionService is managed by the SafeBrowsingService,
-  // since its running state and lifecycle depends on SafeBrowsingService's.
-  // Accessed on UI thread.
-  std::unique_ptr<ClientSideDetectionService> csd_service_;
-
-  // The DownloadProtectionService is managed by the SafeBrowsingService,
-  // since its running state and lifecycle depends on SafeBrowsingService's.
-  // Accessed on UI thread.
-  std::unique_ptr<DownloadProtectionService> download_service_;
-
-#if defined(FULL_SAFE_BROWSING)
-  std::unique_ptr<IncidentReportingService> incident_service_;
-#endif
-
   // The UI manager handles showing interstitials.  Accessed on both UI and IO
   // thread.
   scoped_refptr<SafeBrowsingUIManager> ui_manager_;
@@ -308,10 +282,6 @@
   // both UI and IO thread.
   scoped_refptr<SafeBrowsingDatabaseManager> database_manager_;
 
-#if defined(FULL_SAFE_BROWSING)
-  std::unique_ptr<ResourceRequestDetector> resource_request_detector_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(SafeBrowsingService);
 };
 
diff --git a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
index 6e82e97..d5581a1 100644
--- a/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_service_browsertest.cc
@@ -619,15 +619,13 @@
 
   void CreateCSDService() {
 #if defined(SAFE_BROWSING_CSD)
-    ClientSideDetectionService* csd_service =
-        ClientSideDetectionService::Create(NULL);
     SafeBrowsingService* sb_service =
         g_browser_process->safe_browsing_service();
 
     // A CSD service should already exist.
-    EXPECT_TRUE(sb_service->csd_service_);
+    EXPECT_TRUE(sb_service->safe_browsing_detection_service());
 
-    sb_service->csd_service_.reset(csd_service);
+    sb_service->services_delegate_->InitializeCsdService(nullptr);
     sb_service->RefreshState();
 #endif
   }
diff --git a/chrome/browser/safe_browsing/services_delegate.h b/chrome/browser/safe_browsing/services_delegate.h
new file mode 100644
index 0000000..084068ca
--- /dev/null
+++ b/chrome/browser/safe_browsing/services_delegate.h
@@ -0,0 +1,99 @@
+// 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_SAFE_BROWSING_SERVICES_DELEGATE_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_H_
+
+#include <memory>
+
+#include "chrome/browser/safe_browsing/incident_reporting/delayed_analysis_callback.h"
+#include "components/user_prefs/tracked/tracked_preference_validation_delegate.h"
+
+class Profile;
+
+namespace content {
+class DownloadManager;
+}
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace safe_browsing {
+
+class ClientSideDetectionService;
+class DownloadProtectionService;
+class IncidentReportingService;
+class ResourceRequestDetector;
+struct ResourceRequestInfo;
+class SafeBrowsingService;
+
+// Abstraction to help organize code for mobile vs full safe browsing modes.
+// This helper class should be owned by a SafeBrowsingService, and it handles
+// responsibilities for safe browsing service classes that may or may not exist
+// for a given build config. e.g. No DownloadProtectionService on mobile.
+// ServicesDelegate lives on the UI thread.
+class ServicesDelegate {
+ public:
+  // Used for tests to override service creation. If CanCreateFooService()
+  // returns true, then ServicesDelegate will use the service created by
+  // CreateFooService(). If CanCreateFooService() returns false, then
+  // ServicesDelegate will use its built-in service creation code.
+  class ServicesCreator {
+   public:
+    virtual bool CanCreateDownloadProtectionService() = 0;
+    virtual bool CanCreateIncidentReportingService() = 0;
+    virtual bool CanCreateResourceRequestDetector() = 0;
+
+    // Caller takes ownership of the returned object. Cannot use std::unique_ptr
+    // because services may not be implemented for some build configs.
+    virtual DownloadProtectionService* CreateDownloadProtectionService() = 0;
+    virtual IncidentReportingService* CreateIncidentReportingService() = 0;
+    virtual ResourceRequestDetector* CreateResourceRequestDetector() = 0;
+  };
+
+  // Creates the ServicesDelegate using its's default ServicesCreator.
+  // |safe_browsing_service| is the delegate's owner.
+  static std::unique_ptr<ServicesDelegate> Create(
+      SafeBrowsingService* safe_browsing_service);
+
+  // Creates the ServicesDelegate using a custom ServicesCreator, for testing.
+  static std::unique_ptr<ServicesDelegate> CreateForTest(
+      SafeBrowsingService* safe_browsing_service,
+      ServicesDelegate::ServicesCreator* services_creator);
+
+  virtual ~ServicesDelegate() {}
+
+  // Creates the CSD service for the given |context_getter|.
+  virtual void InitializeCsdService(
+      net::URLRequestContextGetter* context_getter) = 0;
+
+  // Initializes services using the ServicesCreator.
+  virtual void InitializeServices() = 0;
+
+  // Shuts down the download service.
+  virtual void ShutdownServices() = 0;
+
+  // Handles SafeBrowsingService::RefreshState() for the provided services.
+  virtual void RefreshState(bool enable) = 0;
+
+  // See the SafeBrowsingService methods of the same name.
+  virtual void ProcessResourceRequest(const ResourceRequestInfo* request) = 0;
+  virtual std::unique_ptr<TrackedPreferenceValidationDelegate>
+      CreatePreferenceValidationDelegate(Profile* profile) = 0;
+  virtual void RegisterDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) = 0;
+  virtual void RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) = 0;
+  virtual void AddDownloadManager(
+      content::DownloadManager* download_manager) = 0;
+
+  // Returns nullptr for any service that is not available.
+  virtual ClientSideDetectionService* GetCsdService() = 0;
+  virtual DownloadProtectionService* GetDownloadService() = 0;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_H_
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.cc b/chrome/browser/safe_browsing/services_delegate_impl.cc
new file mode 100644
index 0000000..ae6cfdaa
--- /dev/null
+++ b/chrome/browser/safe_browsing/services_delegate_impl.cc
@@ -0,0 +1,153 @@
+// 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/safe_browsing/services_delegate_impl.h"
+
+#include <utility>
+
+#include "base/command_line.h"
+#include "base/memory/ptr_util.h"
+#include "chrome/browser/safe_browsing/safe_browsing_service.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+
+namespace safe_browsing {
+
+// static
+std::unique_ptr<ServicesDelegate> ServicesDelegate::Create(
+    SafeBrowsingService* safe_browsing_service) {
+  return base::WrapUnique(
+      new ServicesDelegateImpl(safe_browsing_service, nullptr));
+}
+
+// static
+std::unique_ptr<ServicesDelegate> ServicesDelegate::CreateForTest(
+    SafeBrowsingService* safe_browsing_service,
+    ServicesDelegate::ServicesCreator* services_creator) {
+  return base::WrapUnique(
+      new ServicesDelegateImpl(safe_browsing_service, services_creator));
+}
+
+ServicesDelegateImpl::ServicesDelegateImpl(
+    SafeBrowsingService* safe_browsing_service,
+    ServicesDelegate::ServicesCreator* services_creator)
+    : safe_browsing_service_(safe_browsing_service),
+      services_creator_(services_creator) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+ServicesDelegateImpl::~ServicesDelegateImpl() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+}
+
+void ServicesDelegateImpl::InitializeCsdService(
+    net::URLRequestContextGetter* context_getter) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+#if defined(SAFE_BROWSING_CSD)
+  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kDisableClientSidePhishingDetection)) {
+    csd_service_.reset(ClientSideDetectionService::Create(context_getter));
+  }
+#endif  // defined(SAFE_BROWSING_CSD)
+}
+
+void ServicesDelegateImpl::InitializeServices() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  download_service_.reset(
+      (services_creator_ &&
+       services_creator_->CanCreateDownloadProtectionService())
+          ? services_creator_->CreateDownloadProtectionService()
+          : CreateDownloadProtectionService());
+  incident_service_.reset(
+      (services_creator_ &&
+       services_creator_->CanCreateIncidentReportingService())
+          ? services_creator_->CreateIncidentReportingService()
+          : CreateIncidentReportingService());
+  resource_request_detector_.reset(
+      (services_creator_ &&
+       services_creator_->CanCreateResourceRequestDetector())
+          ? services_creator_->CreateResourceRequestDetector()
+          : CreateResourceRequestDetector());
+}
+
+void ServicesDelegateImpl::ShutdownServices() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // The IO thread is going away, so make sure the ClientSideDetectionService
+  // dtor executes now since it may call the dtor of URLFetcher which relies
+  // on it.
+  csd_service_.reset();
+
+  resource_request_detector_.reset();
+  incident_service_.reset();
+
+  // Must shut down last.
+  download_service_.reset();
+}
+
+void ServicesDelegateImpl::RefreshState(bool enable) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (csd_service_)
+    csd_service_->SetEnabledAndRefreshState(enable);
+  if (download_service_)
+    download_service_->SetEnabled(enable);
+}
+
+void ServicesDelegateImpl::ProcessResourceRequest(
+    const ResourceRequestInfo* request) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  if (resource_request_detector_)
+    resource_request_detector_->ProcessResourceRequest(request);
+}
+
+std::unique_ptr<TrackedPreferenceValidationDelegate>
+ServicesDelegateImpl::CreatePreferenceValidationDelegate(Profile* profile) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return incident_service_->CreatePreferenceValidationDelegate(profile);
+}
+
+void ServicesDelegateImpl::RegisterDelayedAnalysisCallback(
+    const DelayedAnalysisCallback& callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  incident_service_->RegisterDelayedAnalysisCallback(callback);
+}
+
+void ServicesDelegateImpl::RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+    const DelayedAnalysisCallback& callback) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  incident_service_->RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+      callback);
+}
+
+void ServicesDelegateImpl::AddDownloadManager(
+    content::DownloadManager* download_manager) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  incident_service_->AddDownloadManager(download_manager);
+}
+
+ClientSideDetectionService* ServicesDelegateImpl::GetCsdService() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return csd_service_.get();
+}
+
+DownloadProtectionService* ServicesDelegateImpl::GetDownloadService() {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  return download_service_.get();
+}
+
+DownloadProtectionService*
+ServicesDelegateImpl::CreateDownloadProtectionService() {
+  return new DownloadProtectionService(safe_browsing_service_);
+}
+
+IncidentReportingService*
+ServicesDelegateImpl::CreateIncidentReportingService() {
+  return new IncidentReportingService(safe_browsing_service_);
+}
+
+ResourceRequestDetector* ServicesDelegateImpl::CreateResourceRequestDetector() {
+  return new ResourceRequestDetector(safe_browsing_service_->database_manager(),
+                                     incident_service_->GetIncidentReceiver());
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate_impl.h b/chrome/browser/safe_browsing/services_delegate_impl.h
new file mode 100644
index 0000000..19e024b4
--- /dev/null
+++ b/chrome/browser/safe_browsing/services_delegate_impl.h
@@ -0,0 +1,62 @@
+// 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_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_
+
+#include <memory>
+
+#include "base/macros.h"
+#include "chrome/browser/safe_browsing/client_side_detection_service.h"
+#include "chrome/browser/safe_browsing/download_protection_service.h"
+#include "chrome/browser/safe_browsing/incident_reporting/incident_reporting_service.h"
+#include "chrome/browser/safe_browsing/incident_reporting/resource_request_detector.h"
+#include "chrome/browser/safe_browsing/services_delegate.h"
+
+namespace safe_browsing {
+
+// Actual ServicesDelegate implementation. Create via
+// ServicesDelegate::Create().
+class ServicesDelegateImpl : public ServicesDelegate {
+ public:
+  ServicesDelegateImpl(SafeBrowsingService* safe_browsing_service,
+                       ServicesDelegate::ServicesCreator* services_creator);
+  ~ServicesDelegateImpl() override;
+
+ private:
+  // ServicesDelegate:
+  void InitializeCsdService(
+      net::URLRequestContextGetter* context_getter) override;
+  void InitializeServices() override;
+  void ShutdownServices() override;
+  void RefreshState(bool enable) override;
+  void ProcessResourceRequest(const ResourceRequestInfo* request) override;
+  std::unique_ptr<TrackedPreferenceValidationDelegate>
+      CreatePreferenceValidationDelegate(Profile* profile) override;
+  void RegisterDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) override;
+  void RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) override;
+  void AddDownloadManager(content::DownloadManager* download_manager) override;
+  ClientSideDetectionService* GetCsdService() override;
+  DownloadProtectionService* GetDownloadService() override;
+
+  DownloadProtectionService* CreateDownloadProtectionService();
+  IncidentReportingService* CreateIncidentReportingService();
+  ResourceRequestDetector* CreateResourceRequestDetector();
+
+  std::unique_ptr<ClientSideDetectionService> csd_service_;
+  std::unique_ptr<DownloadProtectionService> download_service_;
+  std::unique_ptr<IncidentReportingService> incident_service_;
+  std::unique_ptr<ResourceRequestDetector> resource_request_detector_;
+
+  SafeBrowsingService* const safe_browsing_service_;
+  ServicesDelegate::ServicesCreator* const services_creator_;
+
+  DISALLOW_COPY_AND_ASSIGN(ServicesDelegateImpl);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_IMPL_H_
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.cc b/chrome/browser/safe_browsing/services_delegate_stub.cc
new file mode 100644
index 0000000..562fd9e
--- /dev/null
+++ b/chrome/browser/safe_browsing/services_delegate_stub.cc
@@ -0,0 +1,64 @@
+// 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/safe_browsing/services_delegate_stub.h"
+
+#include "base/logging.h"
+#include "base/memory/ptr_util.h"
+
+namespace safe_browsing {
+
+// static
+std::unique_ptr<ServicesDelegate> ServicesDelegate::Create(
+    SafeBrowsingService* safe_browsing_service) {
+  return base::WrapUnique(new ServicesDelegateStub);
+}
+
+// static
+std::unique_ptr<ServicesDelegate> ServicesDelegate::CreateForTest(
+    SafeBrowsingService* safe_browsing_service,
+    ServicesDelegate::ServicesCreator* services_creator) {
+  NOTREACHED();
+  return base::WrapUnique(new ServicesDelegateStub);
+}
+
+ServicesDelegateStub::ServicesDelegateStub() {}
+
+ServicesDelegateStub::~ServicesDelegateStub() {}
+
+void ServicesDelegateStub::InitializeCsdService(
+    net::URLRequestContextGetter* context_getter) {}
+
+void ServicesDelegateStub::InitializeServices() {}
+
+void ServicesDelegateStub::ShutdownServices() {}
+
+void ServicesDelegateStub::RefreshState(bool enable) {}
+
+void ServicesDelegateStub::ProcessResourceRequest(
+    const ResourceRequestInfo* request) {}
+
+std::unique_ptr<TrackedPreferenceValidationDelegate>
+ServicesDelegateStub::CreatePreferenceValidationDelegate(Profile* profile) {
+  return std::unique_ptr<TrackedPreferenceValidationDelegate>();
+}
+
+void ServicesDelegateStub::RegisterDelayedAnalysisCallback(
+    const DelayedAnalysisCallback& callback) {}
+
+void ServicesDelegateStub::RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+    const DelayedAnalysisCallback& callback) {}
+
+void ServicesDelegateStub::AddDownloadManager(
+    content::DownloadManager* download_manager) {}
+
+ClientSideDetectionService* ServicesDelegateStub::GetCsdService() {
+  return nullptr;
+}
+
+DownloadProtectionService* ServicesDelegateStub::GetDownloadService() {
+  return nullptr;
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/services_delegate_stub.h b/chrome/browser/safe_browsing/services_delegate_stub.h
new file mode 100644
index 0000000..431068f
--- /dev/null
+++ b/chrome/browser/safe_browsing/services_delegate_stub.h
@@ -0,0 +1,42 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_
+#define CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_
+
+#include "base/macros.h"
+#include "chrome/browser/safe_browsing/services_delegate.h"
+
+namespace safe_browsing {
+
+// Dummy ServicesDelegate implementation. Create via ServicesDelegate::Create().
+class ServicesDelegateStub : public ServicesDelegate {
+ public:
+  ServicesDelegateStub();
+  ~ServicesDelegateStub() override;
+
+ private:
+  // ServicesDelegate:
+  void InitializeCsdService(
+      net::URLRequestContextGetter* context_getter) override;
+  void InitializeServices() override;
+  void ShutdownServices() override;
+  void RefreshState(bool enable) override;
+  void ProcessResourceRequest(const ResourceRequestInfo* request) override;
+  std::unique_ptr<TrackedPreferenceValidationDelegate>
+      CreatePreferenceValidationDelegate(Profile* profile) override;
+  void RegisterDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) override;
+  void RegisterExtendedReportingOnlyDelayedAnalysisCallback(
+      const DelayedAnalysisCallback& callback) override;
+  void AddDownloadManager(content::DownloadManager* download_manager) override;
+  ClientSideDetectionService* GetCsdService() override;
+  DownloadProtectionService* GetDownloadService() override;
+
+  DISALLOW_COPY_AND_ASSIGN(ServicesDelegateStub);
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_SAFE_BROWSING_SERVICES_DELEGATE_STUB_H_
diff --git a/chrome/browser/ui/browser_dialogs.h b/chrome/browser/ui/browser_dialogs.h
index 2eececf..b2a206eff 100644
--- a/chrome/browser/ui/browser_dialogs.h
+++ b/chrome/browser/ui/browser_dialogs.h
@@ -103,6 +103,10 @@
                                     const GURL& url,
                                     bool newly_bookmarked);
 
+// Bridging methods that show/hide the toolkit-views based Task Manager on Mac.
+void ShowTaskManagerViews(Browser* browser);
+void HideTaskManagerViews();
+
 #endif  // OS_MACOSX
 
 #if defined(TOOLKIT_VIEWS)
diff --git a/chrome/browser/ui/cocoa/browser_window_controller.mm b/chrome/browser/ui/cocoa/browser_window_controller.mm
index 3288732..0cabe30 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller.mm
@@ -363,23 +363,7 @@
     // Allow bar visibility to be changed.
     [self enableBarVisibilityUpdates];
 
-    // Set the window to participate in Lion Fullscreen mode.  Setting this flag
-    // has no effect on Snow Leopard or earlier.  Panels can share a fullscreen
-    // space with a tabbed window, but they can not be primary fullscreen
-    // windows.
-    // This ensures the fullscreen button is appropriately positioned. It must
-    // be done before calling layoutSubviews because the new avatar button's
-    // position depends on the fullscreen button's position, as well as
-    // TabStripController's rightIndentForControls.
-    // The fullscreen button's position may depend on the old avatar button's
-    // width, but that does not require calling layoutSubviews first.
-    NSUInteger collectionBehavior = [window collectionBehavior];
-    collectionBehavior |=
-       browser_->type() == Browser::TYPE_TABBED ||
-           browser_->type() == Browser::TYPE_POPUP ?
-               NSWindowCollectionBehaviorFullScreenPrimary :
-               NSWindowCollectionBehaviorFullScreenAuxiliary;
-    [window setCollectionBehavior:collectionBehavior];
+    [self updateFullscreenCollectionBehavior];
 
     [self layoutSubviews];
 
@@ -1205,7 +1189,8 @@
   NSWindow* sourceWindow = [draggedTab window];
   NSRect windowRect = [sourceWindow frame];
   NSScreen* screen = [sourceWindow screen];
-  windowRect.origin.y = NSHeight([screen frame]) - NSMaxY(windowRect);
+  windowRect.origin.y =
+      NSHeight([screen frame]) - NSMaxY(windowRect) + [self menubarOffset];
   gfx::Rect browserRect(windowRect.origin.x, windowRect.origin.y,
                         NSWidth(windowRect), NSHeight(windowRect));
 
@@ -1245,6 +1230,19 @@
           [newBrowser->window()->GetNativeWindow() delegate]);
   DCHECK(controller && [controller isKindOfClass:[TabWindowController class]]);
 
+  // Ensure that the window will appear on top of the source window in
+  // fullscreen mode.
+  if ([self isInAppKitFullscreen]) {
+    NSWindow* window = [controller window];
+    NSUInteger collectionBehavior = [window collectionBehavior];
+    collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
+    collectionBehavior |= NSWindowCollectionBehaviorFullScreenAuxiliary;
+    [window setCollectionBehavior:collectionBehavior];
+    [window setLevel:NSFloatingWindowLevel];
+
+    controller->savedRegularWindowFrame_ = savedRegularWindowFrame_;
+  }
+
   // And make sure we use the correct frame in the new view.
   TabStripController* tabStripController = [controller tabStripController];
   NSView* tabStrip = [self tabStripView];
@@ -1269,6 +1267,25 @@
   return controller;
 }
 
+- (void)detachedWindowEnterFullscreenIfNeeded:(TabWindowController*)source {
+  // Ensure that this is only called when the tab is detached into its own
+  // window (in which the overlay window will be present).
+  DCHECK([self overlayWindow]);
+
+  if (([[source window] styleMask] & NSFullScreenWindowMask)
+      == NSFullScreenWindowMask) {
+    [self updateFullscreenCollectionBehavior];
+
+    // Since the detached window in fullscreen will have the size of the
+    // screen, it will set |savedRegularWindowFrame_| to the screen size after
+    // it enters fullscreen. Make sure that we have the correct value for the
+    // |savedRegularWindowFrame_|.
+    NSRect regularWindowFrame = savedRegularWindowFrame_;
+    [[self window] toggleFullScreen:nil];
+    savedRegularWindowFrame_ = regularWindowFrame;
+  }
+}
+
 - (void)insertPlaceholderForTab:(TabView*)tab
                           frame:(NSRect)frame {
   [super insertPlaceholderForTab:tab frame:frame];
@@ -1292,11 +1309,13 @@
 }
 
 - (BOOL)tabTearingAllowed {
-  return ![self isInAnyFullscreenMode];
+  return ![self isInAnyFullscreenMode] ||
+         base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kEnableFullscreenTabDetaching);
 }
 
 - (BOOL)windowMovementAllowed {
-  return ![self isInAnyFullscreenMode];
+  return ![self isInAnyFullscreenMode] || [self overlayWindow];
 }
 
 - (BOOL)isTabFullyVisible:(TabView*)tab {
@@ -1908,6 +1927,10 @@
           enteringAppKitFullscreen_);
 }
 
+- (CGFloat)menubarOffset {
+  return [presentationModeController_ menubarOffset];
+}
+
 - (void)enterExtensionFullscreen {
   if (chrome::mac::SupportsSystemFullscreen()) {
     [self enterBrowserFullscreenWithToolbar:NO];
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.h b/chrome/browser/ui/cocoa/browser_window_controller_private.h
index 124ffbe..b23ed5d 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.h
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.h
@@ -28,6 +28,10 @@
 // tabs are enabled. Replaces the current controller.
 - (void)createTabStripController;
 
+// Sets the window's collection behavior to the appropriate
+// fullscreen behavior.
+- (void)updateFullscreenCollectionBehavior;
+
 // Saves the window's position in the local state preferences.
 - (void)saveWindowPositionIfNeeded;
 
@@ -52,7 +56,6 @@
 // otherwise.
 - (BOOL)placeBookmarkBarBelowInfoBar;
 
-
 // Lays out the tab content area in the given frame. If the height changes,
 // sends a message to the renderer to resize.
 - (void)layoutTabContentArea:(NSRect)frame;
diff --git a/chrome/browser/ui/cocoa/browser_window_controller_private.mm b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
index 64adb65..87aa090a 100644
--- a/chrome/browser/ui/cocoa/browser_window_controller_private.mm
+++ b/chrome/browser/ui/cocoa/browser_window_controller_private.mm
@@ -124,6 +124,28 @@
           delegate:self]);
 }
 
+- (void)updateFullscreenCollectionBehavior {
+  // Set the window to participate in Lion Fullscreen mode.  Setting this flag
+  // has no effect on Snow Leopard or earlier.  Panels can share a fullscreen
+  // space with a tabbed window, but they can not be primary fullscreen
+  // windows.
+  // This ensures the fullscreen button is appropriately positioned. It must
+  // be done before calling layoutSubviews because the new avatar button's
+  // position depends on the fullscreen button's position, as well as
+  // TabStripController's rightIndentForControls.
+  // The fullscreen button's position may depend on the old avatar button's
+  // width, but that does not require calling layoutSubviews first.
+  NSWindow* window = [self window];
+  NSUInteger collectionBehavior = [window collectionBehavior];
+  collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenAuxiliary;
+  collectionBehavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
+  collectionBehavior |= browser_->type() == Browser::TYPE_TABBED ||
+                                browser_->type() == Browser::TYPE_POPUP
+                            ? NSWindowCollectionBehaviorFullScreenPrimary
+                            : NSWindowCollectionBehaviorFullScreenAuxiliary;
+  [window setCollectionBehavior:collectionBehavior];
+}
+
 - (void)saveWindowPositionIfNeeded {
   if (!chrome::ShouldSaveWindowPlacement(browser_.get()))
     return;
diff --git a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
index dd32269..64b8d28 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_strip_drag_controller.mm
@@ -365,8 +365,8 @@
     // to take into consideration the difference in height.
     NSRect targetFrame = [[targetController_ window] frame];
     NSRect sourceFrame = [dragWindow_ frame];
-    origin.y = NSMinY(targetFrame) +
-                (NSHeight(targetFrame) - NSHeight(sourceFrame));
+    origin.y = NSMinY(targetFrame) + [targetController_ menubarOffset] +
+               (NSHeight(targetFrame) - NSHeight(sourceFrame));
   }
   [dragWindow_ setFrameOrigin:
       NSMakePoint(origin.x + horizDragOffset_, origin.y)];
@@ -446,7 +446,11 @@
     [draggedController_ removeOverlay];
   } else {
     // Only move the window around on screen. Make sure it's set back to
-    // normal state (fully opaque, has shadow, has key, etc).
+    // normal state (fully opaque, has shadow, has key, in fullscreen if
+    // appropriate, etc).
+    [draggedController_
+        detachedWindowEnterFullscreenIfNeeded:sourceController_];
+
     [draggedController_ removeOverlay];
     // Don't want to re-show the window if it was closed during the drag.
     if ([dragWindow_ isVisible]) {
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
index 0a5f724..4bd2b13 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.h
@@ -123,6 +123,11 @@
 - (void)moveTabViews:(NSArray*)views
       fromController:(TabWindowController*)controller;
 
+// Called if the tab is in a detached window and has finished dragging.
+// If the source window is in fullscreen, the detached window will also
+// enter fullscreen.
+- (void)detachedWindowEnterFullscreenIfNeeded:(TabWindowController*)source;
+
 // Number of tabs in the tab strip. Useful, for example, to know if we're
 // dragging the only tab in the window. This includes pinned tabs (both live
 // and not).
@@ -149,6 +154,10 @@
 // Gets whether a particular tab is draggable between windows.
 - (BOOL)isTabDraggable:(NSView*)tabView;
 
+// In any fullscreen mode, the y offset to use for the content at the top of
+// the screen (tab strip, omnibox, bookmark bar, etc). Ranges from 0 to -22.
+- (CGFloat)menubarOffset;
+
 // Tell the window that it needs to call performClose: as soon as the current
 // drag is complete. This prevents a window (and its overlay) from going away
 // during a drag.
diff --git a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
index 01dcdc0..07baee6 100644
--- a/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
+++ b/chrome/browser/ui/cocoa/tabs/tab_window_controller.mm
@@ -255,6 +255,11 @@
   return NULL;
 }
 
+- (void)detachedWindowEnterFullscreenIfNeeded:(TabWindowController*)source {
+  // Subclasses should implement this.
+  NOTIMPLEMENTED();
+}
+
 - (void)insertPlaceholderForTab:(TabView*)tab frame:(NSRect)frame {
   [self showNewTabButton:NO];
 }
@@ -307,6 +312,12 @@
   return NO;
 }
 
+- (CGFloat)menubarOffset {
+  // Subclasses should implement this.
+  NOTIMPLEMENTED();
+  return 0;
+}
+
 - (NSString*)activeTabTitle {
   // subclass must implement
   NOTIMPLEMENTED();
diff --git a/chrome/browser/ui/cocoa/task_manager_mac.mm b/chrome/browser/ui/cocoa/task_manager_mac.mm
index 81df98f..853389b 100644
--- a/chrome/browser/ui/cocoa/task_manager_mac.mm
+++ b/chrome/browser/ui/cocoa/task_manager_mac.mm
@@ -14,6 +14,7 @@
 #include "base/strings/sys_string_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_dialogs.h"
 #import "chrome/browser/ui/cocoa/window_size_autosaver.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
@@ -594,10 +595,20 @@
 
 // Declared in browser_dialogs.h.
 void ShowTaskManager(Browser* browser) {
+  if (chrome::ToolkitViewsDialogsEnabled()) {
+    chrome::ShowTaskManagerViews(browser);
+    return;
+  }
+
   TaskManagerMac::Show();
 }
 
 void HideTaskManager() {
+  if (chrome::ToolkitViewsDialogsEnabled()) {
+    chrome::HideTaskManagerViews();
+    return;
+  }
+
   TaskManagerMac::Hide();
 }
 
diff --git a/chrome/browser/ui/startup/startup_browser_creator_impl.cc b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
index 6ac0bc79..7a9817fd 100644
--- a/chrome/browser/ui/startup/startup_browser_creator_impl.cc
+++ b/chrome/browser/ui/startup/startup_browser_creator_impl.cc
@@ -161,7 +161,7 @@
     std::string appdata_path;
     env->GetVar("USERPROFILE", &appdata_path);
     if (!appdata_path.empty() &&
-        shortcut.find(base::ASCIIToUTF16(appdata_path)) != base::string16::npos)
+        shortcut.find(base::UTF8ToUTF16(appdata_path)) != base::string16::npos)
       return LM_SHORTCUT_DESKTOP;
     return LM_SHORTCUT_UNKNOWN;
   }
diff --git a/chrome/browser/ui/views/browser_dialogs_views_mac.cc b/chrome/browser/ui/views/browser_dialogs_views_mac.cc
index 54cc2579..ac876fe1 100644
--- a/chrome/browser/ui/views/browser_dialogs_views_mac.cc
+++ b/chrome/browser/ui/views/browser_dialogs_views_mac.cc
@@ -9,6 +9,7 @@
 #include "chrome/browser/ui/browser_dialogs.h"
 #include "chrome/browser/ui/views/bookmarks/bookmark_bubble_view.h"
 #include "chrome/browser/ui/views/content_setting_bubble_contents.h"
+#include "chrome/browser/ui/views/new_task_manager_view.h"
 #include "chrome/browser/ui/views/website_settings/website_settings_popup_view.h"
 
 // This file provides definitions of desktop browser dialog-creation methods for
@@ -45,6 +46,17 @@
                                  browser->profile(), url, already_bookmarked);
 }
 
+void ShowTaskManagerViews(Browser* browser) {
+  // On platforms other than Mac, the new task manager is shown unless
+  // explicitly disabled. Assume that running with ToolkitViewsDialogsEnabled()
+  // on Mac also means the new task manager is desired.
+  task_management::NewTaskManagerView::Show(browser);
+}
+
+void HideTaskManagerViews() {
+  task_management::NewTaskManagerView::Hide();
+}
+
 void ContentSettingBubbleViewsBridge::Show(gfx::NativeView parent_view,
                                            ContentSettingBubbleModel* model,
                                            content::WebContents* web_contents,
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index 8f4e094..1da5065 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -9,7 +9,6 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "build/build_config.h"
-#include "chrome/browser/history/web_history_service_factory.h"
 #include "chrome/browser/prefs/incognito_mode_prefs.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/signin_manager_factory.h"
@@ -111,8 +110,6 @@
                              IDS_HISTORY_ACTION_MENU_DESCRIPTION);
   source->AddLocalizedString("removeFromHistory", IDS_HISTORY_REMOVE_PAGE);
   source->AddLocalizedString("moreFromSite", IDS_HISTORY_MORE_FROM_SITE);
-  source->AddLocalizedString("groupByDomainLabel",
-                             IDS_HISTORY_GROUP_BY_DOMAIN_LABEL);
   source->AddLocalizedString("rangeLabel", IDS_HISTORY_RANGE_LABEL);
   source->AddLocalizedString("rangeAllTime", IDS_HISTORY_RANGE_ALL_TIME);
   source->AddLocalizedString("rangeWeek", IDS_HISTORY_RANGE_WEEK);
@@ -121,11 +118,7 @@
   source->AddLocalizedString("rangeNext", IDS_HISTORY_RANGE_NEXT);
   source->AddLocalizedString("rangePrevious", IDS_HISTORY_RANGE_PREVIOUS);
   source->AddLocalizedString("numberVisits", IDS_HISTORY_NUMBER_VISITS);
-  source->AddLocalizedString("filterAllowed", IDS_HISTORY_FILTER_ALLOWED);
   source->AddLocalizedString("filterBlocked", IDS_HISTORY_FILTER_BLOCKED);
-  source->AddLocalizedString("inContentPack", IDS_HISTORY_IN_CONTENT_PACK);
-  source->AddLocalizedString("allowItems", IDS_HISTORY_FILTER_ALLOW_ITEMS);
-  source->AddLocalizedString("blockItems", IDS_HISTORY_FILTER_BLOCK_ITEMS);
   source->AddLocalizedString("blockedVisitText",
                              IDS_HISTORY_BLOCKED_VISIT_TEXT);
   source->AddLocalizedString("hasSyncedResults",
@@ -140,8 +133,6 @@
                              IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON);
   source->AddLocalizedString("bookmarked", IDS_HISTORY_ENTRY_BOOKMARKED);
   source->AddLocalizedString("entrySummary", IDS_HISTORY_ENTRY_SUMMARY);
-  source->AddBoolean("isFullHistorySyncEnabled",
-                     WebHistoryServiceFactory::GetForProfile(profile) != NULL);
   bool group_by_domain = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kHistoryEnableGroupByDomain);
   // Supervised users get the "group by domain" version, but not on mobile,
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 64edd6e..3333a36 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -531,9 +531,9 @@
       {"displayInThisLanguage",
        IDS_SETTINGS_LANGUAGES_DISPLAY_IN_THIS_LANGUAGE},
       {"offerToTranslateInThisLanguage",
-       IDS_OPTIONS_LANGUAGES_OFFER_TO_TRANSLATE_IN_THIS_LANGUAGE},
+       IDS_SETTINGS_LANGUAGES_OFFER_TO_TRANSLATE_IN_THIS_LANGUAGE},
       {"cannotTranslateInThisLanguage",
-       IDS_OPTIONS_LANGUAGES_CANNOT_TRANSLATE_IN_THIS_LANGUAGE},
+       IDS_SETTINGS_LANGUAGES_CANNOT_TRANSLATE_IN_THIS_LANGUAGE},
       {"editDictionaryPageTitle", IDS_SETTINGS_LANGUAGES_EDIT_DICTIONARY_TITLE},
       {"addDictionaryWordLabel", IDS_SETTINGS_LANGUAGES_ADD_DICTIONARY_WORD},
       {"addDictionaryWordButton",
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index aaccdc6..c2a0138e 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -2522,8 +2522,7 @@
       'browser/safe_browsing/safe_browsing_blocking_page.h',
       'browser/safe_browsing/safe_browsing_service.cc',
       'browser/safe_browsing/safe_browsing_service.h',
-      'browser/safe_browsing/safe_browsing_util.cc',
-      'browser/safe_browsing/safe_browsing_util.h',
+      'browser/safe_browsing/services_delegate.h',
       'browser/safe_browsing/threat_details.cc',
       'browser/safe_browsing/threat_details.h',
       'browser/safe_browsing/threat_details_cache.cc',
@@ -2538,6 +2537,8 @@
     'chrome_browser_safe_browsing_mobile_sources': [
       'browser/renderer_host/safe_browsing_resource_throttle.cc',
       'browser/renderer_host/safe_browsing_resource_throttle.h',
+      'browser/safe_browsing/services_delegate_stub.cc',
+      'browser/safe_browsing/services_delegate_stub.h',
     ],
     # "Safe Browsing Full" files in addition to the "basic" ones to use for
     # full safe browsing. This has some in common with "mobile."
@@ -2639,10 +2640,14 @@
       'browser/safe_browsing/safe_browsing_store.h',
       'browser/safe_browsing/safe_browsing_store_file.cc',
       'browser/safe_browsing/safe_browsing_store_file.h',
+      'browser/safe_browsing/safe_browsing_util.cc',
+      'browser/safe_browsing/safe_browsing_util.h',
       'browser/safe_browsing/sandboxed_dmg_analyzer_mac.cc',
       'browser/safe_browsing/sandboxed_dmg_analyzer_mac.h',
       'browser/safe_browsing/sandboxed_zip_analyzer.cc',
       'browser/safe_browsing/sandboxed_zip_analyzer.h',
+      'browser/safe_browsing/services_delegate_impl.cc',
+      'browser/safe_browsing/services_delegate_impl.h',
       'browser/safe_browsing/signature_evaluator_mac.h',
       'browser/safe_browsing/signature_evaluator_mac.mm',
       'browser/safe_browsing/two_phase_uploader.cc',
@@ -3345,7 +3350,6 @@
             '../media/media.gyp:media',
             '../media/midi/midi.gyp:midi',
             '../media/mojo/interfaces/mojo_bindings.gyp:platform_verification_api',
-            '../mojo/mojo_base.gyp:mojo_application_base',
             '../mojo/mojo_base.gyp:mojo_common_lib',
             '../mojo/mojo_base.gyp:mojo_url_type_converters',
             '../mojo/mojo_edk.gyp:mojo_system_impl',
@@ -3354,6 +3358,7 @@
             '../mojo/mojo_public.gyp:mojo_message_pump_lib',
             '../net/net.gyp:net_extras',
             '../net/net.gyp:net_with_v8',
+            '../services/shell/shell.gyp:shell_public',
             '../storage/storage_browser.gyp:storage',
             '../storage/storage_common.gyp:storage_common',
             '../third_party/re2/re2.gyp:re2',
diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi
index df5226c..071b576 100644
--- a/chrome/chrome_browser_ui.gypi
+++ b/chrome/chrome_browser_ui.gypi
@@ -2142,6 +2142,8 @@
       'browser/ui/views/login_handler_views.cc',
       'browser/ui/views/login_view.cc',
       'browser/ui/views/login_view.h',
+      'browser/ui/views/new_task_manager_view.cc',
+      'browser/ui/views/new_task_manager_view.h',
       'browser/ui/views/sync/bubble_sync_promo_view.cc',
       'browser/ui/views/sync/bubble_sync_promo_view.h',
       'browser/ui/views/website_settings/chosen_object_view.cc',
@@ -2388,8 +2390,6 @@
       'browser/ui/views/location_bar/zoom_bubble_view.h',
       'browser/ui/views/location_bar/zoom_view.cc',
       'browser/ui/views/location_bar/zoom_view.h',
-      'browser/ui/views/new_task_manager_view.cc',
-      'browser/ui/views/new_task_manager_view.h',
       'browser/ui/views/omnibox/omnibox_popup_contents_view.cc',
       'browser/ui/views/omnibox/omnibox_popup_contents_view.h',
       'browser/ui/views/omnibox/omnibox_result_view.cc',
diff --git a/chrome/chrome_common.gypi b/chrome/chrome_common.gypi
index 9ded65f..4c5b4598 100644
--- a/chrome/chrome_common.gypi
+++ b/chrome/chrome_common.gypi
@@ -405,8 +405,8 @@
             'common_mojo_bindings',
             '<(DEPTH)/components/components.gyp:autofill_core_common',
             '<(DEPTH)/components/components.gyp:autofill_content_common',
+            '<(DEPTH)/components/components.gyp:password_manager_content_mojo_bindings',
             '<(DEPTH)/components/components.gyp:password_manager_core_common',
-            '<(DEPTH)/components/components.gyp:password_manager_content_common',
             '<(DEPTH)/components/components.gyp:signin_core_common',
             '<(DEPTH)/components/components.gyp:translate_content_common',
             '<(DEPTH)/components/components.gyp:visitedlink_common',
diff --git a/chrome/common/BUILD.gn b/chrome/common/BUILD.gn
index 4a08381e..363da304 100644
--- a/chrome/common/BUILD.gn
+++ b/chrome/common/BUILD.gn
@@ -139,7 +139,7 @@
       "//chrome/common/net",
       "//components/autofill/content/common",
       "//components/autofill/core/common",
-      "//components/password_manager/content/common",
+      "//components/password_manager/content/public/interfaces",
       "//components/password_manager/core/common",
       "//components/signin/core/common",
       "//components/translate/content/common",
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index cf343b9..64a43400 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1159,6 +1159,9 @@
 // Enables custom Cmd+` window cycling for platform apps and hosted apps.
 const char kEnableAppWindowCycling[] = "enable-app-window-cycling";
 
+// Enables tab detaching in fullscreen mode on Mac.
+const char kEnableFullscreenTabDetaching[] = "enable-fullscreen-tab-detaching";
+
 // Allows hosted apps to be opened in windows on Mac.
 const char kEnableHostedAppsInWindows[] = "enable-hosted-apps-in-windows";
 
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index ddd744d..6ae3495 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -336,6 +336,7 @@
 extern const char kDisableTranslateNewUX[];
 extern const char kEnableAppInfoDialogMac[];
 extern const char kEnableAppWindowCycling[];
+extern const char kEnableFullscreenTabDetaching[];
 extern const char kEnableHostedAppsInWindows[];
 extern const char kEnableMacViewsNativeAppWindows[];
 extern const char kEnableMacViewsDialogs[];
diff --git a/chrome/test/base/mojo_test_connector.cc b/chrome/test/base/mojo_test_connector.cc
index d261057..21fa403 100644
--- a/chrome/test/base/mojo_test_connector.cc
+++ b/chrome/test/base/mojo_test_connector.cc
@@ -18,7 +18,7 @@
 #include "mojo/edk/embedder/platform_channel_pair.h"
 #include "mojo/edk/embedder/process_delegate.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/store.h"
 #include "services/shell/background/tests/test_catalog_store.h"
 #include "services/shell/native_runner_delegate.h"
 #include "services/shell/public/cpp/connector.h"
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index ed5e7045..881e6f8 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-8181.0.0
\ No newline at end of file
+8184.0.0
\ No newline at end of file
diff --git a/components/BUILD.gn b/components/BUILD.gn
index 2f721df..999d71d0 100644
--- a/components/BUILD.gn
+++ b/components/BUILD.gn
@@ -398,7 +398,6 @@
       "//components/dom_distiller/core",
       "//components/dom_distiller/core:test_support",
       "//components/password_manager/content/browser",
-      "//components/password_manager/content/common",
       "//components/password_manager/content/renderer",
       "//components/strings",
       "//components/tracing",
diff --git a/components/components_tests.gyp b/components/components_tests.gyp
index e344102..313d8b0 100644
--- a/components/components_tests.gyp
+++ b/components/components_tests.gyp
@@ -457,7 +457,7 @@
     ],
     'password_manager_unittest_sources': [
       'password_manager/content/browser/content_password_manager_driver_unittest.cc',
-      'password_manager/content/browser/credential_manager_dispatcher_unittest.cc',
+      'password_manager/content/browser/credential_manager_impl_unittest.cc',
       'password_manager/core/browser/affiliated_match_helper_unittest.cc',
       'password_manager/core/browser/affiliation_backend_unittest.cc',
       'password_manager/core/browser/affiliation_database_unittest.cc',
@@ -1261,7 +1261,6 @@
             'components.gyp:page_load_metrics_browser',
             'components.gyp:page_load_metrics_renderer',
             'components.gyp:password_manager_content_browser',
-            'components.gyp:password_manager_content_common',
             'components.gyp:power',
             'components.gyp:precache_content',
             'components.gyp:safe_browsing_db',
diff --git a/components/content_settings/core/common/content_settings_pattern_unittest.cc b/components/content_settings/core/common/content_settings_pattern_unittest.cc
index c21658d..74e6019 100644
--- a/components/content_settings/core/common/content_settings_pattern_unittest.cc
+++ b/components/content_settings/core/common/content_settings_pattern_unittest.cc
@@ -620,25 +620,38 @@
   EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
             Pattern("https://mail.google.com:*").Compare(
                 Pattern("*://mail.google.com:80")));
+}
 
-  // Test the wildcard pattern.
+TEST(ContentSettingsPatternTest, CompareWithWildcard) {
   EXPECT_EQ(ContentSettingsPattern::IDENTITY,
             ContentSettingsPattern::Wildcard().Compare(
                 ContentSettingsPattern::Wildcard()));
+  EXPECT_EQ(ContentSettingsPattern::IDENTITY,
+            ContentSettingsPattern::Wildcard().Compare(Pattern("*")));
 
   EXPECT_EQ(ContentSettingsPattern::PREDECESSOR,
             Pattern("[*.]google.com").Compare(
                 ContentSettingsPattern::Wildcard()));
+  EXPECT_EQ(ContentSettingsPattern::PREDECESSOR,
+            Pattern("[*.]google.com").Compare(Pattern("*")));
+
   EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
             ContentSettingsPattern::Wildcard().Compare(
                  Pattern("[*.]google.com")));
+  EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
+            Pattern("*").Compare(Pattern("[*.]google.com")));
 
   EXPECT_EQ(ContentSettingsPattern::PREDECESSOR,
             Pattern("mail.google.com").Compare(
                 ContentSettingsPattern::Wildcard()));
+  EXPECT_EQ(ContentSettingsPattern::PREDECESSOR,
+            Pattern("mail.google.com").Compare(Pattern("*")));
+
   EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
             ContentSettingsPattern::Wildcard().Compare(
                  Pattern("mail.google.com")));
+  EXPECT_EQ(ContentSettingsPattern::SUCCESSOR,
+            Pattern("*").Compare(Pattern("mail.google.com")));
 }
 
 // Legacy tests to ensure backwards compatibility.
diff --git a/components/filesystem/BUILD.gn b/components/filesystem/BUILD.gn
index 76e61ff..9744522d 100644
--- a/components/filesystem/BUILD.gn
+++ b/components/filesystem/BUILD.gn
@@ -47,8 +47,8 @@
     "//mojo/platform_handle:for_shared_library",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
   ]
 
   data_deps = [
diff --git a/components/filesystem/DEPS b/components/filesystem/DEPS
index fed9a5c..7c2a2481 100644
--- a/components/filesystem/DEPS
+++ b/components/filesystem/DEPS
@@ -1,9 +1,9 @@
 include_rules = [
   "+components/prefs",
   "+mojo/common",
-  "+services/shell",
   "+mojo/platform_handle",
   "+mojo/public",
-  "+mojo/services/tracing/public/cpp",
   "+mojo/util",
+  "+services/shell",
+  "+services/tracing/public/cpp",
 ]
diff --git a/components/filesystem/file_system_app.h b/components/filesystem/file_system_app.h
index 467fb3d..62b2c70 100644
--- a/components/filesystem/file_system_app.h
+++ b/components/filesystem/file_system_app.h
@@ -10,9 +10,9 @@
 #include "components/filesystem/file_system_impl.h"
 #include "components/filesystem/lock_table.h"
 #include "components/filesystem/public/interfaces/file_system.mojom.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace mojo {
 class Connector;
diff --git a/components/filesystem/filesystem.gyp b/components/filesystem/filesystem.gyp
index c0c45f28..7ec313a 100644
--- a/components/filesystem/filesystem.gyp
+++ b/components/filesystem/filesystem.gyp
@@ -31,11 +31,10 @@
       ],
       'dependencies': [
         'filesystem_bindings',
-        '../../mojo/mojo_base.gyp:mojo_application_base',
-        '../../mojo/mojo_base.gyp:mojo_application_bindings',
         '../../mojo/mojo_edk.gyp:mojo_system_impl',
         '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
         '../../mojo/mojo_platform_handle.gyp:platform_handle',
+        '../../services/shell/shell.gyp:shell_public',
         '../../url/url.gyp:url_lib',
       ],
       'export_dependent_settings': [
diff --git a/components/font_service/BUILD.gn b/components/font_service/BUILD.gn
index 3a34f7c4..fcd3b99 100644
--- a/components/font_service/BUILD.gn
+++ b/components/font_service/BUILD.gn
@@ -17,8 +17,8 @@
     "//mojo/common:common_base",
     "//mojo/platform_handle",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
   ]
 
   public_deps = [
diff --git a/components/font_service/DEPS b/components/font_service/DEPS
index 3ad5945..74754cf8 100644
--- a/components/font_service/DEPS
+++ b/components/font_service/DEPS
@@ -4,7 +4,7 @@
   "+mojo/message_pump",
   "+mojo/platform_handle",
   "+mojo/public",
-  "+mojo/services/tracing/public/cpp",
+  "+services/tracing/public/cpp",
   "+skia",
   "+third_party/skia/include",
 ]
diff --git a/components/font_service/font_service_app.cc b/components/font_service/font_service_app.cc
index 30a287ce..f4d17086 100644
--- a/components/font_service/font_service_app.cc
+++ b/components/font_service/font_service_app.cc
@@ -11,19 +11,12 @@
 #include "mojo/platform_handle/platform_handle_functions.h"
 #include "services/shell/public/cpp/connection.h"
 
-static_assert(static_cast<uint32_t>(SkTypeface::kNormal) ==
-                  static_cast<uint32_t>(font_service::TypefaceStyle::NORMAL),
+static_assert(static_cast<uint32_t>(SkFontStyle::kUpright_Slant) ==
+                  static_cast<uint32_t>(font_service::TypefaceSlant::ROMAN),
               "Skia and font service flags must match");
-static_assert(static_cast<uint32_t>(SkTypeface::kBold) ==
-                  static_cast<uint32_t>(font_service::TypefaceStyle::BOLD),
+static_assert(static_cast<uint32_t>(SkFontStyle::kItalic_Slant) ==
+                  static_cast<uint32_t>(font_service::TypefaceSlant::ITALIC),
               "Skia and font service flags must match");
-static_assert(static_cast<uint32_t>(SkTypeface::kItalic) ==
-                  static_cast<uint32_t>(font_service::TypefaceStyle::ITALIC),
-              "Skia and font service flags must match");
-static_assert(
-    static_cast<uint32_t>(SkTypeface::kBoldItalic) ==
-        static_cast<uint32_t>(font_service::TypefaceStyle::BOLD_ITALIC),
-    "Skia and font service flags must match");
 
 namespace {
 
@@ -75,19 +68,26 @@
 }
 
 void FontServiceApp::MatchFamilyName(const mojo::String& family_name,
-                                     TypefaceStyle requested_style,
+                                     TypefaceStylePtr requested_style,
                                      const MatchFamilyNameCallback& callback) {
   SkFontConfigInterface::FontIdentity result_identity;
   SkString result_family;
-  SkTypeface::Style result_style;
+  SkFontStyle result_style;
   SkFontConfigInterface* fc =
       SkFontConfigInterface::GetSingletonDirectInterface();
   const bool r = fc->matchFamilyName(
-      family_name.data(), static_cast<SkTypeface::Style>(requested_style),
+      family_name.data(),
+      SkFontStyle(requested_style->weight,
+                  requested_style->width,
+                  static_cast<SkFontStyle::Slant>(requested_style->slant)),
       &result_identity, &result_family, &result_style);
 
   if (!r) {
-    callback.Run(nullptr, "", TypefaceStyle::NORMAL);
+    TypefaceStylePtr style(TypefaceStyle::New());
+    style->weight = SkFontStyle().weight();
+    style->width = SkFontStyle().width();
+    style->slant = static_cast<TypefaceSlant>(SkFontStyle().slant());
+    callback.Run(nullptr, "", std::move(style));
     return;
   }
 
@@ -100,8 +100,12 @@
   identity->ttc_index = result_identity.fTTCIndex;
   identity->str_representation = result_identity.fString.c_str();
 
-  callback.Run(std::move(identity), result_family.c_str(),
-               static_cast<TypefaceStyle>(result_style));
+  TypefaceStylePtr style(TypefaceStyle::New());
+  style->weight = result_style.weight();
+  style->width = result_style.width();
+  style->slant = static_cast<TypefaceSlant>(result_style.slant());
+
+  callback.Run(std::move(identity), result_family.c_str(), std::move(style));
 }
 
 void FontServiceApp::OpenStream(uint32_t id_number,
diff --git a/components/font_service/font_service_app.h b/components/font_service/font_service_app.h
index fcafa78..da89269 100644
--- a/components/font_service/font_service_app.h
+++ b/components/font_service/font_service_app.h
@@ -11,9 +11,9 @@
 #include "base/macros.h"
 #include "components/font_service/public/interfaces/font_service.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 #include "skia/ext/skia_utils_base.h"
 
 namespace font_service {
@@ -37,7 +37,7 @@
 
   // FontService:
   void MatchFamilyName(const mojo::String& family_name,
-                       TypefaceStyle requested_style,
+                       TypefaceStylePtr requested_style,
                        const MatchFamilyNameCallback& callback) override;
   void OpenStream(uint32_t id_number,
                   const OpenStreamCallback& callback) override;
diff --git a/components/font_service/public/cpp/font_loader.cc b/components/font_service/public/cpp/font_loader.cc
index 3bd1828..b70a802 100644
--- a/components/font_service/public/cpp/font_loader.cc
+++ b/components/font_service/public/cpp/font_loader.cc
@@ -27,10 +27,10 @@
 }
 
 bool FontLoader::matchFamilyName(const char family_name[],
-                                 SkTypeface::Style requested,
+                                 SkFontStyle requested,
                                  FontIdentity* out_font_identifier,
                                  SkString* out_family_name,
-                                 SkTypeface::Style* out_style) {
+                                 SkFontStyle* out_style) {
   TRACE_EVENT1("font_service", "FontServiceThread::MatchFamilyName",
                "family_name", family_name);
   return thread_->MatchFamilyName(family_name, requested, out_font_identifier,
diff --git a/components/font_service/public/cpp/font_loader.h b/components/font_service/public/cpp/font_loader.h
index 557241f..ba79e09 100644
--- a/components/font_service/public/cpp/font_loader.h
+++ b/components/font_service/public/cpp/font_loader.h
@@ -43,10 +43,10 @@
 
   // SkFontConfigInterface:
   bool matchFamilyName(const char family_name[],
-                       SkTypeface::Style requested,
+                       SkFontStyle requested,
                        FontIdentity* out_font_identifier,
                        SkString* out_family_name,
-                       SkTypeface::Style* out_style) override;
+                       SkFontStyle* out_style) override;
   SkStreamAsset* openStream(const FontIdentity& identity) override;
 
  private:
diff --git a/components/font_service/public/cpp/font_service_thread.cc b/components/font_service/public/cpp/font_service_thread.cc
index d5c3618..496d415 100644
--- a/components/font_service/public/cpp/font_service_thread.cc
+++ b/components/font_service/public/cpp/font_service_thread.cc
@@ -31,10 +31,10 @@
 
 bool FontServiceThread::MatchFamilyName(
     const char family_name[],
-    SkTypeface::Style requested_style,
+    SkFontStyle requested_style,
     SkFontConfigInterface::FontIdentity* out_font_identity,
     SkString* out_family_name,
-    SkTypeface::Style* out_style) {
+    SkFontStyle* out_style) {
   DCHECK_NE(GetThreadId(), base::PlatformThread::CurrentId());
 
   bool out_valid = false;
@@ -85,15 +85,20 @@
 void FontServiceThread::MatchFamilyNameImpl(
     base::WaitableEvent* done_event,
     const char family_name[],
-    SkTypeface::Style requested_style,
+    SkFontStyle requested_style,
     bool* out_valid,
     SkFontConfigInterface::FontIdentity* out_font_identity,
     SkString* out_family_name,
-    SkTypeface::Style* out_style) {
+    SkFontStyle* out_style) {
   DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
 
+  TypefaceStylePtr style(TypefaceStyle::New());
+  style->weight = requested_style.weight();
+  style->width = requested_style.width();
+  style->slant = static_cast<TypefaceSlant>(requested_style.slant());
+
   font_service_->MatchFamilyName(
-      mojo::String(family_name), static_cast<TypefaceStyle>(requested_style),
+      mojo::String(family_name), std::move(style),
       base::Bind(&FontServiceThread::OnMatchFamilyNameComplete, this,
                  done_event, out_valid, out_font_identity, out_family_name,
                  out_style));
@@ -104,10 +109,10 @@
     bool* out_valid,
     SkFontConfigInterface::FontIdentity* out_font_identity,
     SkString* out_family_name,
-    SkTypeface::Style* out_style,
+    SkFontStyle* out_style,
     FontIdentityPtr font_identity,
     mojo::String family_name,
-    TypefaceStyle style) {
+    TypefaceStylePtr style) {
   DCHECK_EQ(GetThreadId(), base::PlatformThread::CurrentId());
 
   *out_valid = font_identity;
@@ -119,7 +124,9 @@
     // behaviour of the current Linux IPC version.
 
     *out_family_name = family_name.data();
-    *out_style = static_cast<SkTypeface::Style>(style);
+    *out_style = SkFontStyle(style->weight,
+                             style->width,
+                             static_cast<SkFontStyle::Slant>(style->slant));
   }
 
   done_event->Signal();
diff --git a/components/font_service/public/cpp/font_service_thread.h b/components/font_service/public/cpp/font_service_thread.h
index 2ec4dbd..04c75a2 100644
--- a/components/font_service/public/cpp/font_service_thread.h
+++ b/components/font_service/public/cpp/font_service_thread.h
@@ -35,10 +35,10 @@
   // These methods are proxies which run on your thread, post a blocking task
   // to the FontServiceThread, and wait on an event signaled from the callback.
   bool MatchFamilyName(const char family_name[],
-                       SkTypeface::Style requested_style,
+                       SkFontStyle requested_style,
                        SkFontConfigInterface::FontIdentity* out_font_identity,
                        SkString* out_family_name,
-                       SkTypeface::Style* out_style);
+                       SkFontStyle* out_style);
   scoped_refptr<MappedFontFile> OpenStream(
       const SkFontConfigInterface::FontIdentity& identity);
 
@@ -52,11 +52,11 @@
   void MatchFamilyNameImpl(
       base::WaitableEvent* done_event,
       const char family_name[],
-      SkTypeface::Style requested_style,
+      SkFontStyle requested_style,
       bool* out_valid,
       SkFontConfigInterface::FontIdentity* out_font_identity,
       SkString* out_family_name,
-      SkTypeface::Style* out_style);
+      SkFontStyle* out_style);
 
   // Called on the FontServiceThread in response to receiving a message from
   // our MatchFamily mojo IPC. This writes the data returned by mojo, and then
@@ -66,10 +66,10 @@
       bool* out_valid,
       SkFontConfigInterface::FontIdentity* out_font_identity,
       SkString* out_family_name,
-      SkTypeface::Style* out_style,
+      SkFontStyle* out_style,
       FontIdentityPtr font_identity,
       mojo::String family_name,
-      TypefaceStyle style);
+      TypefaceStylePtr style);
 
   // Implementation of OpenStream; same threading restrictions as MatchFamily.
   void OpenStreamImpl(base::WaitableEvent* done_event,
diff --git a/components/font_service/public/interfaces/font_service.mojom b/components/font_service/public/interfaces/font_service.mojom
index 3d53b000..7b9bc31b4 100644
--- a/components/font_service/public/interfaces/font_service.mojom
+++ b/components/font_service/public/interfaces/font_service.mojom
@@ -4,11 +4,15 @@
 
 module font_service;
 
-enum TypefaceStyle {
-  NORMAL = 0,
-  BOLD = 0x01,
-  ITALIC = 0x02,
-  BOLD_ITALIC = 0x03
+enum TypefaceSlant {
+  ROMAN = 0,
+  ITALIC = 1,
+};
+
+struct TypefaceStyle {
+  uint16 weight;
+  uint8 width;
+  TypefaceSlant slant;
 };
 
 // A reference to specific font on the font service.
diff --git a/components/history_strings.grdp b/components/history_strings.grdp
index 99328f17..585e086 100644
--- a/components/history_strings.grdp
+++ b/components/history_strings.grdp
@@ -34,33 +34,18 @@
   <message name="IDS_HISTORY_ENTRY_SUMMARY" desc="Summary of all the fields in a history entry (time, whether the entry is bookmarked, title, and domain).">
     <ph name="TIME"><ex>3:14</ex>$1</ph> <ph name="BOOKMARKED"><ex>bookmarked</ex>$2</ph> <ph name="TITLE"><ex>PI: The Magical Number</ex>$3</ph> <ph name="DOMAIN"><ex>pi.com</ex>$4</ph>
   </message>
-  <message name="IDS_HISTORY_FILTER_ALLOW_ITEMS" desc="Title of the button that allows the user to allow the selected history items">
-    Allow items
-  </message>
-  <message name="IDS_HISTORY_FILTER_ALLOWED" desc="Text that shows that an entry is allowed.">
-    Allowed
-  </message>
-  <message name="IDS_HISTORY_FILTER_BLOCK_ITEMS" desc="Title of the button that allows the user to block the selected history items">
-    Block items
-  </message>
   <message name="IDS_HISTORY_FILTER_BLOCKED" desc="Text that shows that an entry is blocked.">
     Blocked
   </message>
   <message name="IDS_HISTORY_FOUND_SEARCH_RESULTS" desc="Message shown when zero or multiple search results are found.">
     Found <ph name="NUMBER_OF_RESULTS">$1</ph> <ph name="SEARCH_RESULTS"><ex>search results</ex>$2</ph> for '<ph name="SEARCH_STRING">$3</ph>'.
   </message>
-  <message name="IDS_HISTORY_GROUP_BY_DOMAIN_LABEL" desc="Label for the checkbox that toggles the mode to group history visits by domain.">
-    Group domains
-  </message>
   <message name="IDS_HISTORY_HAS_SYNCED_RESULTS" desc="The notification at the top of the history page indicating that it is showing visits synced from other devices.">
     Showing history from your signed-in devices. <ph name="BEGIN_LINK">&lt;a href="https://support.google.com/chrome/?p=sync_history&amp;hl=[GRITLANGCODE]"&gt;</ph>Learn more<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
   </message>
   <message name="IDS_HISTORY_OTHER_FORMS_OF_HISTORY" desc="The notification at the top of the history page indicating that deleting Chrome browsing history will not delete other forms of history stored at Google My Activity.">
     Your Google Account may have other forms of browsing history at <ph name="BEGIN_LINK">&lt;a target="_blank" href="$1"&gt;</ph>history.google.com<ph name="END_LINK">&lt;/a&gt;</ph>.
   </message>
-  <message name="IDS_HISTORY_IN_CONTENT_PACK" desc="Text that shows that an entry is in a content pack.">
-    In content pack
-  </message>
   <message name="IDS_HISTORY_INTERVAL" desc="A history interval shown in the title. The dates are already localized strings.">
     <ph name="START_DATE">$1<ex>Wednesday, Aug. 1, 2012</ex></ph> to <ph name="END_DATE">$2<ex>Thursday, Aug. 30, 2012</ex></ph>
   </message>
diff --git a/components/leveldb/BUILD.gn b/components/leveldb/BUILD.gn
index b2ae5e6..77097ef5 100644
--- a/components/leveldb/BUILD.gn
+++ b/components/leveldb/BUILD.gn
@@ -44,8 +44,8 @@
     "//mojo/platform_handle:for_shared_library",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
   ]
 
   data_deps = [
diff --git a/components/leveldb/DEPS b/components/leveldb/DEPS
index bfd4af7..bd058d6b 100644
--- a/components/leveldb/DEPS
+++ b/components/leveldb/DEPS
@@ -4,8 +4,8 @@
   "+mojo/message_pump",
   "+mojo/platform_handle",
   "+mojo/public",
-  "+mojo/services/tracing/public/cpp",
-  "+services/shell",
   "+mojo/util",
+  "+services/shell",
+  "+services/tracing/public/cpp",
   "+third_party/leveldatabase",
 ]
diff --git a/components/leveldb/leveldb.gyp b/components/leveldb/leveldb.gyp
index 6d1a8ef..440b7b4a 100644
--- a/components/leveldb/leveldb.gyp
+++ b/components/leveldb/leveldb.gyp
@@ -30,8 +30,8 @@
       'dependencies': [
         'leveldb_public_lib',
         '../../components/filesystem/filesystem.gyp:filesystem_lib',
-        '../../mojo/mojo_base.gyp:mojo_application_base',
         '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../../services/shell/shell.gyp:shell_public',
         '../../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
       ]
     },
@@ -47,9 +47,9 @@
       ],
       'dependencies': [
         'leveldb_bindings_mojom',
-        '../../mojo/mojo_base.gyp:mojo_application_base',
         '../../mojo/mojo_edk.gyp:mojo_system_impl',
         '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../../services/shell/shell.gyp:shell_public',
         '../../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
       ]
     },
diff --git a/components/leveldb/leveldb_app.h b/components/leveldb/leveldb_app.h
index a607199..5c127a1 100644
--- a/components/leveldb/leveldb_app.h
+++ b/components/leveldb/leveldb_app.h
@@ -7,9 +7,9 @@
 
 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace leveldb {
 
diff --git a/components/leveldb/leveldb_service_unittest.cc b/components/leveldb/leveldb_service_unittest.cc
index 4e0ec28..6acd0f85 100644
--- a/components/leveldb/leveldb_service_unittest.cc
+++ b/components/leveldb/leveldb_service_unittest.cc
@@ -58,7 +58,13 @@
   DISALLOW_COPY_AND_ASSIGN(LevelDBServiceTest);
 };
 
-TEST_F(LevelDBServiceTest, Basic) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_Basic DISABLED_Basic
+#else
+#define MAYBE_Basic Basic
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_Basic) {
   filesystem::DirectoryPtr directory;
   GetUserDataDir(&directory);
 
@@ -103,7 +109,13 @@
   EXPECT_EQ("", value.To<std::string>());
 }
 
-TEST_F(LevelDBServiceTest, WriteBatch) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_WriteBatch DISABLED_WriteBatch
+#else
+#define MAYBE_WriteBatch WriteBatch
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_WriteBatch) {
   filesystem::DirectoryPtr directory;
   GetUserDataDir(&directory);
 
@@ -156,7 +168,13 @@
   EXPECT_EQ("more", value.To<std::string>());
 }
 
-TEST_F(LevelDBServiceTest, Reconnect) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_Reconnect DISABLED_Reconnect
+#else
+#define MAYBE_Reconnect Reconnect
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_Reconnect) {
   DatabaseError error;
 
   {
@@ -202,7 +220,13 @@
   }
 }
 
-TEST_F(LevelDBServiceTest, GetSnapshotSimple) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_GetSnapshotSimple DISABLED_GetSnapshotSimple
+#else
+#define MAYBE_GetSnapshotSimple GetSnapshotSimple
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_GetSnapshotSimple) {
   DatabaseError error;
 
   filesystem::DirectoryPtr directory;
@@ -220,7 +244,13 @@
   EXPECT_NE(static_cast<uint64_t>(0), snapshot_id);
 }
 
-TEST_F(LevelDBServiceTest, GetFromSnapshots) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_GetFromSnapshots DISABLED_GetFromSnapshots
+#else
+#define MAYBE_GetFromSnapshots GetFromSnapshots
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_GetFromSnapshots) {
   DatabaseError error;
 
   filesystem::DirectoryPtr directory;
@@ -274,7 +304,13 @@
   EXPECT_EQ("value", value.To<std::string>());
 }
 
-TEST_F(LevelDBServiceTest, InvalidArgumentOnInvalidSnapshot) {
+// TODO(crbug.com/602820) Test is flaky.
+#if defined(OS_LINUX)
+#define MAYBE_InvalidArgumentOnInvalidSnapshot DISABLED_InvalidArgumentOnInvalidSnapshot
+#else
+#define MAYBE_InvalidArgumentOnInvalidSnapshot InvalidArgumentOnInvalidSnapshot
+#endif
+TEST_F(LevelDBServiceTest, MAYBE_InvalidArgumentOnInvalidSnapshot) {
   filesystem::DirectoryPtr directory;
   GetUserDataDir(&directory);
 
diff --git a/components/mus/BUILD.gn b/components/mus/BUILD.gn
index 12ad0ab..e3fb4524 100644
--- a/components/mus/BUILD.gn
+++ b/components/mus/BUILD.gn
@@ -21,6 +21,7 @@
     ":resources_strings",
     "//mojo/platform_handle:for_shared_library",
     "//services/shell/public/cpp:sources",
+    "//services/tracing/public/interfaces",
   ]
 
   if (is_win) {
@@ -80,8 +81,8 @@
     "//components/mus/ws:lib",
     "//components/resource_provider/public/cpp",
     "//mojo/common:common_base",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//ui/events",
     "//ui/events/ozone:events_ozone_layout",
     "//ui/gl:gl",
diff --git a/components/mus/DEPS b/components/mus/DEPS
index e1aa5d3..cc7b362 100644
--- a/components/mus/DEPS
+++ b/components/mus/DEPS
@@ -6,8 +6,8 @@
   "+mojo/common",
   "+mojo/converters",
   "+mojo/public",
-  "+mojo/services/tracing/public",
   "+services/shell",
+  "+services/tracing/public",
   "+third_party/skia/include",
   "+ui",
 ]
diff --git a/components/mus/mus_app.cc b/components/mus/mus_app.cc
index dc0b56d..4323fc5a 100644
--- a/components/mus/mus_app.cc
+++ b/components/mus/mus_app.cc
@@ -23,9 +23,9 @@
 #include "components/mus/ws/window_tree_host_factory.h"
 #include "components/resource_provider/public/cpp/resource_loader.h"
 #include "mojo/public/c/system/main.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/connector.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 #include "ui/base/resource/resource_bundle.h"
 #include "ui/base/ui_base_paths.h"
 #include "ui/events/event_switches.h"
diff --git a/components/mus/mus_app.h b/components/mus/mus_app.h
index e77a81bb5..289faca 100644
--- a/components/mus/mus_app.h
+++ b/components/mus/mus_app.h
@@ -21,10 +21,10 @@
 #include "components/mus/ws/platform_display_init_params.h"
 #include "components/mus/ws/user_id.h"
 #include "components/mus/ws/window_server_delegate.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/application_runner.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace mojo {
 class Connector;
diff --git a/components/mus/surfaces/BUILD.gn b/components/mus/surfaces/BUILD.gn
index c4f989f..3c45ca5 100644
--- a/components/mus/surfaces/BUILD.gn
+++ b/components/mus/surfaces/BUILD.gn
@@ -30,8 +30,8 @@
     "//gpu/command_buffer/client:gles2_interface",
     "//mojo/converters/geometry",
     "//mojo/converters/surfaces",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//ui/gfx",
     "//ui/gl",
     "//ui/mojo/geometry:interfaces",
diff --git a/components/mus/ws/BUILD.gn b/components/mus/ws/BUILD.gn
index b88104f..4d7608b82 100644
--- a/components/mus/ws/BUILD.gn
+++ b/components/mus/ws/BUILD.gn
@@ -97,9 +97,9 @@
     "//mojo/converters/input_events",
     "//mojo/converters/surfaces",
     "//mojo/public/cpp/bindings:callback",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
     "//services/shell/public/interfaces",
+    "//services/tracing/public/cpp",
     "//ui/base",
     "//ui/events",
     "//ui/events/platform",
diff --git a/components/password_manager.gypi b/components/password_manager.gypi
index d3b0631..a7e411c 100644
--- a/components/password_manager.gypi
+++ b/components/password_manager.gypi
@@ -249,26 +249,47 @@
     ['OS != "ios"', {
       'targets': [
         {
-          # GN version: //components/password_manager/content/common
-          'target_name': 'password_manager_content_common',
+          # GN version: //components/password_manager/content/public/interfaces
+          'target_name': 'password_manager_content_mojo_bindings_mojom',
+          'type': 'none',
+          'variables': {
+            'mojom_extra_generator_args': [
+              '--typemap', '<(DEPTH)/url/mojo/origin.typemap',
+            ],
+            'mojom_files': [
+              'password_manager/content/public/interfaces/credential_manager.mojom',
+            ],
+          },
+          'include_dirs': [
+            '..',
+          ],
+          'includes': [
+            '../mojo/mojom_bindings_generator_explicit.gypi',
+          ],
+        },
+        {
+          # GN version: //components/password_manager/content/public/cpp
+          'target_name': 'password_manager_content_mojo_bindings',
           'type': 'static_library',
           'dependencies': [
             '../base/base.gyp:base',
-            '../content/content.gyp:content_common',
-            '../ipc/ipc.gyp:ipc',
-            '../third_party/WebKit/public/blink.gyp:blink_minimal',
-            '../url/ipc/url_ipc.gyp:url_ipc',
+            '../mojo/mojo_base.gyp:mojo_common_lib',
+            '../mojo/mojo_base.gyp:mojo_url_type_converters',
+            '../mojo/mojo_public.gyp:mojo_cpp_bindings',
+            '../third_party/WebKit/public/blink.gyp:blink',
+            '../url/url.gyp:url_mojom',
+            'password_manager_content_mojo_bindings_mojom',
             'password_manager_core_common',
           ],
+          'export_dependent_settings': [
+             '../url/url.gyp:url_mojom',
+           ],
           'include_dirs': [
             '..',
           ],
           'sources': [
-            'password_manager/content/common/credential_manager_content_utils.cc',
-            'password_manager/content/common/credential_manager_content_utils.h',
-            'password_manager/content/common/credential_manager_message_generator.cc',
-            'password_manager/content/common/credential_manager_message_generator.h',
-            'password_manager/content/common/credential_manager_messages.h',
+            'password_manager/content/public/cpp/type_converters.cc',
+            'password_manager/content/public/cpp/type_converters.h',
           ],
         },
         {
@@ -278,11 +299,10 @@
           'dependencies': [
             '../base/base.gyp:base',
             '../content/content.gyp:content_common',
-            '../ipc/ipc.gyp:ipc',
+            '../mojo/mojo_base.gyp:mojo_url_type_converters',
             '../third_party/WebKit/public/blink.gyp:blink',
-            '../url/ipc/url_ipc.gyp:url_ipc',
+            'password_manager_content_mojo_bindings',
             'password_manager_core_common',
-            'password_manager_content_common',
           ],
           'include_dirs': [
             '..',
@@ -301,13 +321,14 @@
             '../content/content.gyp:content_browser',
             '../content/content.gyp:content_common',
             '../ipc/ipc.gyp:ipc',
+            '../mojo/mojo_base.gyp:mojo_url_type_converters',
             '../net/net.gyp:net',
             'autofill_content_browser',
             'autofill_content_common',
             'autofill_core_common',
             'keyed_service_content',
+            'password_manager_content_mojo_bindings',
             'password_manager_core_browser',
-            'password_manager_content_common',
           ],
           'include_dirs': [
             '..',
@@ -320,8 +341,8 @@
             'password_manager/content/browser/content_password_manager_driver.h',
             'password_manager/content/browser/content_password_manager_driver_factory.cc',
             'password_manager/content/browser/content_password_manager_driver_factory.h',
-            'password_manager/content/browser/credential_manager_dispatcher.cc',
-            'password_manager/content/browser/credential_manager_dispatcher.h',
+            'password_manager/content/browser/credential_manager_impl.cc',
+            'password_manager/content/browser/credential_manager_impl.h',
             'password_manager/content/browser/password_manager_internals_service_factory.cc',
             'password_manager/content/browser/password_manager_internals_service_factory.h',
           ],
diff --git a/components/password_manager/content/DEPS b/components/password_manager/content/DEPS
index 4d5d19c..6a69bf3 100644
--- a/components/password_manager/content/DEPS
+++ b/components/password_manager/content/DEPS
@@ -2,10 +2,10 @@
   "+components/autofill/content/common",
   "+components/autofill/core/common",
   "+content/public/common",
+  "+mojo/common",
   # Allow inclusion of WebKit API files.
   "+third_party/WebKit/public/platform",
   "+third_party/WebKit/public/web",
-  "+ipc",
 ]
 
 specific_include_rules = {
diff --git a/components/password_manager/content/browser/BUILD.gn b/components/password_manager/content/browser/BUILD.gn
index 85f89dc0..4220c2c 100644
--- a/components/password_manager/content/browser/BUILD.gn
+++ b/components/password_manager/content/browser/BUILD.gn
@@ -10,8 +10,8 @@
     "content_password_manager_driver.h",
     "content_password_manager_driver_factory.cc",
     "content_password_manager_driver_factory.h",
-    "credential_manager_dispatcher.cc",
-    "credential_manager_dispatcher.h",
+    "credential_manager_impl.cc",
+    "credential_manager_impl.h",
     "password_manager_internals_service_factory.cc",
     "password_manager_internals_service_factory.h",
   ]
@@ -22,13 +22,15 @@
     "//components/autofill/content/common",
     "//components/autofill/core/common",
     "//components/keyed_service/content",
-    "//components/password_manager/content/common",
+    "//components/password_manager/content/public/cpp",
+    "//components/password_manager/content/public/interfaces",
     "//components/password_manager/core/browser",
     "//components/password_manager/core/common",
     "//components/prefs",
     "//content/public/browser",
     "//content/public/common",
     "//ipc",
+    "//mojo/common:url_type_converters",
     "//net",
   ]
 }
@@ -37,7 +39,7 @@
   testonly = true
   sources = [
     "content_password_manager_driver_unittest.cc",
-    "credential_manager_dispatcher_unittest.cc",
+    "credential_manager_impl_unittest.cc",
   ]
   deps = [
     ":browser",
diff --git a/components/password_manager/content/browser/DEPS b/components/password_manager/content/browser/DEPS
index 8dac82f..4bab70e2 100644
--- a/components/password_manager/content/browser/DEPS
+++ b/components/password_manager/content/browser/DEPS
@@ -3,5 +3,7 @@
   "+components/autofill/content/browser",
   "+components/keyed_service/content",
   "+content/public/browser",
+  "+ipc",
+  "+mojo/public",
   "+net",
 ]
diff --git a/components/password_manager/content/browser/credential_manager_dispatcher.cc b/components/password_manager/content/browser/credential_manager_dispatcher.cc
deleted file mode 100644
index 6f6780cf..0000000
--- a/components/password_manager/content/browser/credential_manager_dispatcher.cc
+++ /dev/null
@@ -1,292 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/password_manager/content/browser/credential_manager_dispatcher.h"
-
-#include <utility>
-
-#include "base/bind.h"
-#include "base/strings/string16.h"
-#include "base/strings/utf_string_conversions.h"
-#include "components/autofill/core/common/password_form.h"
-#include "components/password_manager/content/browser/content_password_manager_driver.h"
-#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
-#include "components/password_manager/content/common/credential_manager_messages.h"
-#include "components/password_manager/core/browser/affiliated_match_helper.h"
-#include "components/password_manager/core/browser/password_manager_client.h"
-#include "components/password_manager/core/browser/password_store.h"
-#include "components/password_manager/core/common/credential_manager_types.h"
-#include "components/password_manager/core/common/password_manager_pref_names.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "ipc/ipc_message_macros.h"
-
-namespace password_manager {
-
-// CredentialManagerDispatcher -------------------------------------------------
-
-CredentialManagerDispatcher::CredentialManagerDispatcher(
-    content::WebContents* web_contents,
-    PasswordManagerClient* client)
-    : WebContentsObserver(web_contents), client_(client), weak_factory_(this) {
-  DCHECK(web_contents);
-  auto_signin_enabled_.Init(prefs::kCredentialsEnableAutosignin,
-                            client_->GetPrefs());
-}
-
-CredentialManagerDispatcher::~CredentialManagerDispatcher() {
-}
-
-bool CredentialManagerDispatcher::OnMessageReceived(
-    const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(CredentialManagerDispatcher, message)
-    IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_Store, OnStore);
-    IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_RequireUserMediation,
-                        OnRequireUserMediation);
-    IPC_MESSAGE_HANDLER(CredentialManagerHostMsg_RequestCredential,
-                        OnRequestCredential);
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void CredentialManagerDispatcher::OnStore(
-    int request_id,
-    const password_manager::CredentialInfo& credential) {
-  DCHECK(credential.type != CredentialType::CREDENTIAL_TYPE_EMPTY);
-  DCHECK(request_id);
-  web_contents()->GetRenderViewHost()->Send(
-      new CredentialManagerMsg_AcknowledgeStore(
-          web_contents()->GetRenderViewHost()->GetRoutingID(), request_id));
-
-  if (!client_->IsSavingAndFillingEnabledForCurrentPage())
-    return;
-
-  std::unique_ptr<autofill::PasswordForm> form(
-      CreatePasswordFormFromCredentialInfo(
-          credential, web_contents()->GetLastCommittedURL().GetOrigin()));
-  form->skip_zero_click = !IsZeroClickAllowed();
-
-  form_manager_.reset(new CredentialManagerPasswordFormManager(
-      client_, GetDriver(), *form, this));
-}
-
-void CredentialManagerDispatcher::OnProvisionalSaveComplete() {
-  DCHECK(form_manager_);
-  DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
-  const autofill::PasswordForm& form = form_manager_->pending_credentials();
-
-  if (!form.federation_origin.unique()) {
-    // If this is a federated credential, check it against the federated matches
-    // produced by the PasswordFormManager. If a match is found, update it and
-    // return.
-    for (const auto& match : form_manager_->federated_matches()) {
-      if (match->username_value == form.username_value &&
-          match->federation_origin.IsSameOriginWith(form.federation_origin)) {
-        form_manager_->Update(*match);
-        return;
-      }
-    }
-  } else if (!form_manager_->IsNewLogin()) {
-    // Otherwise, if this is not a new password credential, update the existing
-    // credential without prompting the user. This will also update the
-    // 'skip_zero_click' state, as we've gotten an explicit signal that the page
-    // understands the credential management API and so can be trusted to notify
-    // us when they sign the user out.
-    form_manager_->Update(*form_manager_->preferred_match());
-    return;
-  }
-
-  // Otherwise, this is a new form, so as the user if they'd like to save.
-  client_->PromptUserToSaveOrUpdatePassword(
-      std::move(form_manager_), CredentialSourceType::CREDENTIAL_SOURCE_API,
-      false);
-}
-
-void CredentialManagerDispatcher::OnRequireUserMediation(int request_id) {
-  DCHECK(request_id);
-
-  PasswordStore* store = GetPasswordStore();
-  if (!store || !IsUpdatingCredentialAllowed()) {
-    web_contents()->GetRenderViewHost()->Send(
-        new CredentialManagerMsg_AcknowledgeRequireUserMediation(
-            web_contents()->GetRenderViewHost()->GetRoutingID(), request_id));
-    return;
-  }
-
-  if (store->affiliated_match_helper()) {
-    store->affiliated_match_helper()->GetAffiliatedAndroidRealms(
-        GetSynthesizedFormForOrigin(),
-        base::Bind(&CredentialManagerDispatcher::ScheduleRequireMediationTask,
-                   weak_factory_.GetWeakPtr(), request_id));
-  } else {
-    std::vector<std::string> no_affiliated_realms;
-    ScheduleRequireMediationTask(request_id, no_affiliated_realms);
-  }
-}
-
-void CredentialManagerDispatcher::ScheduleRequireMediationTask(
-    int request_id,
-    const std::vector<std::string>& android_realms) {
-  DCHECK(GetPasswordStore());
-  if (!pending_require_user_mediation_) {
-    pending_require_user_mediation_.reset(
-        new CredentialManagerPendingRequireUserMediationTask(
-            this, web_contents()->GetLastCommittedURL().GetOrigin(),
-            android_realms));
-
-    // This will result in a callback to
-    // CredentialManagerPendingRequireUserMediationTask::OnGetPasswordStoreResults().
-    GetPasswordStore()->GetAutofillableLogins(
-        pending_require_user_mediation_.get());
-  } else {
-    pending_require_user_mediation_->AddOrigin(
-        web_contents()->GetLastCommittedURL().GetOrigin());
-  }
-
-  web_contents()->GetRenderViewHost()->Send(
-      new CredentialManagerMsg_AcknowledgeRequireUserMediation(
-          web_contents()->GetRenderViewHost()->GetRoutingID(), request_id));
-}
-
-void CredentialManagerDispatcher::OnRequestCredential(
-    int request_id,
-    bool zero_click_only,
-    bool include_passwords,
-    const std::vector<GURL>& federations) {
-  DCHECK(request_id);
-  PasswordStore* store = GetPasswordStore();
-  if (pending_request_ || !store) {
-    web_contents()->GetRenderViewHost()->Send(
-        new CredentialManagerMsg_RejectCredentialRequest(
-            web_contents()->GetRenderViewHost()->GetRoutingID(), request_id,
-            pending_request_
-                ? blink::WebCredentialManagerPendingRequestError
-                : blink::WebCredentialManagerPasswordStoreUnavailableError));
-    return;
-  }
-
-  // Return an empty credential if zero-click is required but disabled, or if
-  // the current page has TLS errors.
-  if ((zero_click_only && !IsZeroClickAllowed()) ||
-      client_->DidLastPageLoadEncounterSSLErrors()) {
-    web_contents()->GetRenderViewHost()->Send(
-        new CredentialManagerMsg_SendCredential(
-            web_contents()->GetRenderViewHost()->GetRoutingID(), request_id,
-            CredentialInfo()));
-    return;
-  }
-
-  if (store->affiliated_match_helper()) {
-    store->affiliated_match_helper()->GetAffiliatedAndroidRealms(
-        GetSynthesizedFormForOrigin(),
-        base::Bind(&CredentialManagerDispatcher::ScheduleRequestTask,
-                   weak_factory_.GetWeakPtr(), request_id, zero_click_only,
-                   include_passwords, federations));
-  } else {
-    std::vector<std::string> no_affiliated_realms;
-    ScheduleRequestTask(request_id, zero_click_only, include_passwords,
-                        federations, no_affiliated_realms);
-  }
-}
-
-void CredentialManagerDispatcher::ScheduleRequestTask(
-    int request_id,
-    bool zero_click_only,
-    bool include_passwords,
-    const std::vector<GURL>& federations,
-    const std::vector<std::string>& android_realms) {
-  DCHECK(GetPasswordStore());
-  pending_request_.reset(new CredentialManagerPendingRequestTask(
-      this, request_id, zero_click_only,
-      web_contents()->GetLastCommittedURL().GetOrigin(), include_passwords,
-      federations, android_realms));
-
-  // This will result in a callback to
-  // PendingRequestTask::OnGetPasswordStoreResults().
-  GetPasswordStore()->GetAutofillableLogins(pending_request_.get());
-}
-
-PasswordStore* CredentialManagerDispatcher::GetPasswordStore() {
-  return client_ ? client_->GetPasswordStore() : nullptr;
-}
-
-bool CredentialManagerDispatcher::IsZeroClickAllowed() const {
-  return *auto_signin_enabled_ && !client_->IsOffTheRecord();
-}
-
-GURL CredentialManagerDispatcher::GetOrigin() const {
-  return web_contents()->GetLastCommittedURL().GetOrigin();
-}
-
-base::WeakPtr<PasswordManagerDriver> CredentialManagerDispatcher::GetDriver() {
-  ContentPasswordManagerDriverFactory* driver_factory =
-      ContentPasswordManagerDriverFactory::FromWebContents(web_contents());
-  DCHECK(driver_factory);
-  PasswordManagerDriver* driver =
-      driver_factory->GetDriverForFrame(web_contents()->GetMainFrame());
-  return driver->AsWeakPtr();
-}
-
-void CredentialManagerDispatcher::SendCredential(int request_id,
-                                                 const CredentialInfo& info) {
-  DCHECK(pending_request_);
-  DCHECK_EQ(pending_request_->id(), request_id);
-
-  web_contents()->GetRenderViewHost()->Send(
-      new CredentialManagerMsg_SendCredential(
-          web_contents()->GetRenderViewHost()->GetRoutingID(),
-          pending_request_->id(), info));
-  pending_request_.reset();
-}
-
-void CredentialManagerDispatcher::SendPasswordForm(
-    int request_id,
-    const autofill::PasswordForm* form) {
-  CredentialInfo info;
-  if (form) {
-    password_manager::CredentialType type_to_return =
-        form->federation_origin.unique()
-            ? CredentialType::CREDENTIAL_TYPE_PASSWORD
-            : CredentialType::CREDENTIAL_TYPE_FEDERATED;
-    info = CredentialInfo(*form, type_to_return);
-    if (PasswordStore* store = GetPasswordStore()) {
-      if (form->skip_zero_click && IsZeroClickAllowed()) {
-        DCHECK(IsUpdatingCredentialAllowed());
-        autofill::PasswordForm update_form = *form;
-        update_form.skip_zero_click = false;
-        store->UpdateLogin(update_form);
-      }
-    }
-  }
-  SendCredential(request_id, info);
-}
-
-PasswordManagerClient* CredentialManagerDispatcher::client() const {
-  return client_;
-}
-
-autofill::PasswordForm
-CredentialManagerDispatcher::GetSynthesizedFormForOrigin() const {
-  autofill::PasswordForm synthetic_form;
-  synthetic_form.origin = web_contents()->GetLastCommittedURL().GetOrigin();
-  synthetic_form.signon_realm = synthetic_form.origin.spec();
-  synthetic_form.scheme = autofill::PasswordForm::SCHEME_HTML;
-  synthetic_form.ssl_valid = synthetic_form.origin.SchemeIsCryptographic() &&
-                             !client_->DidLastPageLoadEncounterSSLErrors();
-  return synthetic_form;
-}
-
-void CredentialManagerDispatcher::DoneRequiringUserMediation() {
-  DCHECK(pending_require_user_mediation_);
-  pending_require_user_mediation_.reset();
-}
-
-bool CredentialManagerDispatcher::IsUpdatingCredentialAllowed() const {
-  return !client_->DidLastPageLoadEncounterSSLErrors() &&
-         !client_->IsOffTheRecord();
-}
-
-}  // namespace password_manager
diff --git a/components/password_manager/content/browser/credential_manager_impl.cc b/components/password_manager/content/browser/credential_manager_impl.cc
new file mode 100644
index 0000000..0d5fa0d
--- /dev/null
+++ b/components/password_manager/content/browser/credential_manager_impl.cc
@@ -0,0 +1,281 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/password_manager/content/browser/credential_manager_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "components/autofill/core/common/password_form.h"
+#include "components/password_manager/content/browser/content_password_manager_driver.h"
+#include "components/password_manager/content/browser/content_password_manager_driver_factory.h"
+#include "components/password_manager/content/public/cpp/type_converters.h"
+#include "components/password_manager/core/browser/affiliated_match_helper.h"
+#include "components/password_manager/core/browser/password_manager_client.h"
+#include "components/password_manager/core/browser/password_store.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "components/password_manager/core/common/password_manager_pref_names.h"
+#include "content/public/browser/web_contents.h"
+#include "mojo/common/url_type_converters.h"
+
+namespace password_manager {
+
+namespace {
+
+void RunMojoGetCallback(const mojom::CredentialManager::GetCallback& callback,
+                        const CredentialInfo& info) {
+  mojom::CredentialInfoPtr credential = mojom::CredentialInfo::From(info);
+  callback.Run(mojom::CredentialManagerError::SUCCESS, std::move(credential));
+}
+
+}  // namespace
+
+// CredentialManagerImpl -------------------------------------------------
+
+CredentialManagerImpl::CredentialManagerImpl(content::WebContents* web_contents,
+                                             PasswordManagerClient* client)
+    : WebContentsObserver(web_contents), client_(client), weak_factory_(this) {
+  DCHECK(web_contents);
+  auto_signin_enabled_.Init(prefs::kCredentialsEnableAutosignin,
+                            client_->GetPrefs());
+}
+
+CredentialManagerImpl::~CredentialManagerImpl() {}
+
+void CredentialManagerImpl::BindRequest(
+    mojom::CredentialManagerRequest request) {
+  bindings_.AddBinding(this, std::move(request));
+}
+
+void CredentialManagerImpl::Store(mojom::CredentialInfoPtr credential,
+                                  const StoreCallback& callback) {
+  CredentialInfo info = credential.To<CredentialInfo>();
+  DCHECK_NE(CredentialType::CREDENTIAL_TYPE_EMPTY, info.type);
+
+  // Send acknowledge response back.
+  callback.Run();
+
+  if (!client_->IsSavingAndFillingEnabledForCurrentPage())
+    return;
+
+  std::unique_ptr<autofill::PasswordForm> form(
+      CreatePasswordFormFromCredentialInfo(
+          info, web_contents()->GetLastCommittedURL().GetOrigin()));
+  form->skip_zero_click = !IsZeroClickAllowed();
+
+  form_manager_.reset(new CredentialManagerPasswordFormManager(
+      client_, GetDriver(), *form, this));
+}
+
+void CredentialManagerImpl::OnProvisionalSaveComplete() {
+  DCHECK(form_manager_);
+  DCHECK(client_->IsSavingAndFillingEnabledForCurrentPage());
+  const autofill::PasswordForm& form = form_manager_->pending_credentials();
+
+  if (!form.federation_origin.unique()) {
+    // If this is a federated credential, check it against the federated matches
+    // produced by the PasswordFormManager. If a match is found, update it and
+    // return.
+    for (const auto& match : form_manager_->federated_matches()) {
+      if (match->username_value == form.username_value &&
+          match->federation_origin.IsSameOriginWith(form.federation_origin)) {
+        form_manager_->Update(*match);
+        return;
+      }
+    }
+  } else if (!form_manager_->IsNewLogin()) {
+    // Otherwise, if this is not a new password credential, update the existing
+    // credential without prompting the user. This will also update the
+    // 'skip_zero_click' state, as we've gotten an explicit signal that the page
+    // understands the credential management API and so can be trusted to notify
+    // us when they sign the user out.
+    form_manager_->Update(*form_manager_->preferred_match());
+    return;
+  }
+
+  // Otherwise, this is a new form, so as the user if they'd like to save.
+  client_->PromptUserToSaveOrUpdatePassword(
+      std::move(form_manager_), CredentialSourceType::CREDENTIAL_SOURCE_API,
+      false);
+}
+
+void CredentialManagerImpl::RequireUserMediation(
+    const RequireUserMediationCallback& callback) {
+  PasswordStore* store = GetPasswordStore();
+  if (!store || !IsUpdatingCredentialAllowed()) {
+    callback.Run();
+    return;
+  }
+
+  if (store->affiliated_match_helper()) {
+    store->affiliated_match_helper()->GetAffiliatedAndroidRealms(
+        GetSynthesizedFormForOrigin(),
+        base::Bind(&CredentialManagerImpl::ScheduleRequireMediationTask,
+                   weak_factory_.GetWeakPtr(), callback));
+  } else {
+    std::vector<std::string> no_affiliated_realms;
+    ScheduleRequireMediationTask(callback, no_affiliated_realms);
+  }
+}
+
+void CredentialManagerImpl::ScheduleRequireMediationTask(
+    const RequireUserMediationCallback& callback,
+    const std::vector<std::string>& android_realms) {
+  DCHECK(GetPasswordStore());
+  if (!pending_require_user_mediation_) {
+    pending_require_user_mediation_.reset(
+        new CredentialManagerPendingRequireUserMediationTask(
+            this, web_contents()->GetLastCommittedURL().GetOrigin(),
+            android_realms));
+
+    // This will result in a callback to
+    // CredentialManagerPendingRequireUserMediationTask::
+    // OnGetPasswordStoreResults().
+    GetPasswordStore()->GetAutofillableLogins(
+        pending_require_user_mediation_.get());
+  } else {
+    pending_require_user_mediation_->AddOrigin(
+        web_contents()->GetLastCommittedURL().GetOrigin());
+  }
+
+  // Send acknowledge response back.
+  callback.Run();
+}
+
+void CredentialManagerImpl::Get(bool zero_click_only,
+                                bool include_passwords,
+                                mojo::Array<mojo::String> federations,
+                                const GetCallback& callback) {
+  PasswordStore* store = GetPasswordStore();
+  if (pending_request_ || !store) {
+    // Callback error.
+    callback.Run(pending_request_
+                     ? mojom::CredentialManagerError::PENDINGREQUEST
+                     : mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
+                 nullptr);
+    return;
+  }
+
+  // Return an empty credential if zero-click is required but disabled, or if
+  // the current page has TLS errors.
+  if ((zero_click_only && !IsZeroClickAllowed()) ||
+      client_->DidLastPageLoadEncounterSSLErrors()) {
+    // Callback with empty credential info.
+    callback.Run(mojom::CredentialManagerError::SUCCESS,
+                 mojom::CredentialInfo::New());
+    return;
+  }
+
+  if (store->affiliated_match_helper()) {
+    store->affiliated_match_helper()->GetAffiliatedAndroidRealms(
+        GetSynthesizedFormForOrigin(),
+        base::Bind(&CredentialManagerImpl::ScheduleRequestTask,
+                   weak_factory_.GetWeakPtr(), callback, zero_click_only,
+                   include_passwords, federations.To<std::vector<GURL>>()));
+  } else {
+    std::vector<std::string> no_affiliated_realms;
+    ScheduleRequestTask(callback, zero_click_only, include_passwords,
+                        federations.To<std::vector<GURL>>(),
+                        no_affiliated_realms);
+  }
+}
+
+void CredentialManagerImpl::ScheduleRequestTask(
+    const GetCallback& callback,
+    bool zero_click_only,
+    bool include_passwords,
+    const std::vector<GURL>& federations,
+    const std::vector<std::string>& android_realms) {
+  DCHECK(GetPasswordStore());
+  pending_request_.reset(new CredentialManagerPendingRequestTask(
+      this, base::Bind(&RunMojoGetCallback, callback), zero_click_only,
+      web_contents()->GetLastCommittedURL().GetOrigin(), include_passwords,
+      federations, android_realms));
+
+  // This will result in a callback to
+  // PendingRequestTask::OnGetPasswordStoreResults().
+  GetPasswordStore()->GetAutofillableLogins(pending_request_.get());
+}
+
+PasswordStore* CredentialManagerImpl::GetPasswordStore() {
+  return client_ ? client_->GetPasswordStore() : nullptr;
+}
+
+bool CredentialManagerImpl::IsZeroClickAllowed() const {
+  return *auto_signin_enabled_ && !client_->IsOffTheRecord();
+}
+
+GURL CredentialManagerImpl::GetOrigin() const {
+  return web_contents()->GetLastCommittedURL().GetOrigin();
+}
+
+base::WeakPtr<PasswordManagerDriver> CredentialManagerImpl::GetDriver() {
+  ContentPasswordManagerDriverFactory* driver_factory =
+      ContentPasswordManagerDriverFactory::FromWebContents(web_contents());
+  DCHECK(driver_factory);
+  PasswordManagerDriver* driver =
+      driver_factory->GetDriverForFrame(web_contents()->GetMainFrame());
+  return driver->AsWeakPtr();
+}
+
+void CredentialManagerImpl::SendCredential(
+    const SendCredentialCallback& send_callback,
+    const CredentialInfo& info) {
+  DCHECK(pending_request_);
+  DCHECK(send_callback.Equals(pending_request_->send_callback()));
+
+  send_callback.Run(info);
+  pending_request_.reset();
+}
+
+void CredentialManagerImpl::SendPasswordForm(
+    const SendCredentialCallback& send_callback,
+    const autofill::PasswordForm* form) {
+  CredentialInfo info;
+  if (form) {
+    password_manager::CredentialType type_to_return =
+        form->federation_origin.unique()
+            ? CredentialType::CREDENTIAL_TYPE_PASSWORD
+            : CredentialType::CREDENTIAL_TYPE_FEDERATED;
+    info = CredentialInfo(*form, type_to_return);
+    if (PasswordStore* store = GetPasswordStore()) {
+      if (form->skip_zero_click && IsZeroClickAllowed()) {
+        DCHECK(IsUpdatingCredentialAllowed());
+        autofill::PasswordForm update_form = *form;
+        update_form.skip_zero_click = false;
+        store->UpdateLogin(update_form);
+      }
+    }
+  }
+  SendCredential(send_callback, info);
+}
+
+PasswordManagerClient* CredentialManagerImpl::client() const {
+  return client_;
+}
+
+autofill::PasswordForm CredentialManagerImpl::GetSynthesizedFormForOrigin()
+    const {
+  autofill::PasswordForm synthetic_form;
+  synthetic_form.origin = web_contents()->GetLastCommittedURL().GetOrigin();
+  synthetic_form.signon_realm = synthetic_form.origin.spec();
+  synthetic_form.scheme = autofill::PasswordForm::SCHEME_HTML;
+  synthetic_form.ssl_valid = synthetic_form.origin.SchemeIsCryptographic() &&
+                             !client_->DidLastPageLoadEncounterSSLErrors();
+  return synthetic_form;
+}
+
+void CredentialManagerImpl::DoneRequiringUserMediation() {
+  DCHECK(pending_require_user_mediation_);
+  pending_require_user_mediation_.reset();
+}
+
+bool CredentialManagerImpl::IsUpdatingCredentialAllowed() const {
+  return !client_->DidLastPageLoadEncounterSSLErrors() &&
+         !client_->IsOffTheRecord();
+}
+
+}  // namespace password_manager
diff --git a/components/password_manager/content/browser/credential_manager_dispatcher.h b/components/password_manager/content/browser/credential_manager_impl.h
similarity index 68%
rename from components/password_manager/content/browser/credential_manager_dispatcher.h
rename to components/password_manager/content/browser/credential_manager_impl.h
index 1471a7b7..e6429eb0 100644
--- a/components/password_manager/content/browser/credential_manager_dispatcher.h
+++ b/components/password_manager/content/browser/credential_manager_impl.h
@@ -2,20 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_DISPATCHER_H_
-#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_DISPATCHER_H_
+#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
 
 #include <memory>
 
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
+#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
 #include "components/password_manager/core/browser/credential_manager_pending_request_task.h"
 #include "components/password_manager/core/browser/credential_manager_pending_require_user_mediation_task.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
 #include "components/prefs/pref_member.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 
 class GURL;
 
@@ -34,42 +36,35 @@
 class PasswordStore;
 struct CredentialInfo;
 
-class CredentialManagerDispatcher
-    : public content::WebContentsObserver,
+class CredentialManagerImpl
+    : public mojom::CredentialManager,
+      public content::WebContentsObserver,
       public CredentialManagerPasswordFormManagerDelegate,
       public CredentialManagerPendingRequestTaskDelegate,
       public CredentialManagerPendingRequireUserMediationTaskDelegate {
  public:
-  CredentialManagerDispatcher(content::WebContents* web_contents,
-                              PasswordManagerClient* client);
-  ~CredentialManagerDispatcher() override;
+  CredentialManagerImpl(content::WebContents* web_contents,
+                        PasswordManagerClient* client);
+  ~CredentialManagerImpl() override;
 
-  // Called in response to an IPC from the renderer, triggered by a page's call
-  // to 'navigator.credentials.store'.
-  virtual void OnStore(int request_id, const password_manager::CredentialInfo&);
+  void BindRequest(mojom::CredentialManagerRequest request);
 
-  // Called in response to an IPC from the renderer, triggered by a page's call
-  // to 'navigator.credentials.requireUserMediation'.
-  virtual void OnRequireUserMediation(int request_id);
-
-  // Called in response to an IPC from the renderer, triggered by a page's call
-  // to 'navigator.credentials.request'.
-  //
-  // TODO(vabr): Determine if we can drop the `const` here to save some copies
-  // while processing the request.
-  virtual void OnRequestCredential(int request_id,
-                                   bool zero_click_only,
-                                   bool include_passwords,
-                                   const std::vector<GURL>& federations);
-
-  // content::WebContentsObserver implementation.
-  bool OnMessageReceived(const IPC::Message& message) override;
+  // mojom::CredentialManager methods:
+  void Store(mojom::CredentialInfoPtr credential,
+             const StoreCallback& callback) override;
+  void RequireUserMediation(
+      const RequireUserMediationCallback& callback) override;
+  void Get(bool zero_click_only,
+           bool include_passwords,
+           mojo::Array<mojo::String> federations,
+           const GetCallback& callback) override;
 
   // CredentialManagerPendingRequestTaskDelegate:
   bool IsZeroClickAllowed() const override;
   GURL GetOrigin() const override;
-  void SendCredential(int request_id, const CredentialInfo& info) override;
-  void SendPasswordForm(int request_id,
+  void SendCredential(const SendCredentialCallback& send_callback,
+                      const CredentialInfo& info) override;
+  void SendPasswordForm(const SendCredentialCallback& send_callback,
                         const autofill::PasswordForm* form) override;
   PasswordManagerClient* client() const override;
   autofill::PasswordForm GetSynthesizedFormForOrigin() const override;
@@ -89,7 +84,7 @@
   // Schedules a CredentiaManagerPendingRequestTask (during
   // |OnRequestCredential()|) after the PasswordStore's AffiliationMatchHelper
   // grabs a list of realms related to the current web origin.
-  void ScheduleRequestTask(int request_id,
+  void ScheduleRequestTask(const GetCallback& callback,
                            bool zero_click_only,
                            bool include_passwords,
                            const std::vector<GURL>& federations,
@@ -99,7 +94,7 @@
   // AffiliationMatchHelper grabs a list of realms related to the current
   // web origin.
   void ScheduleRequireMediationTask(
-      int request_id,
+      const RequireUserMediationCallback& callback,
       const std::vector<std::string>& android_realms);
 
   // Returns true iff it's OK to update credentials in the password store.
@@ -119,11 +114,13 @@
   std::unique_ptr<CredentialManagerPendingRequireUserMediationTask>
       pending_require_user_mediation_;
 
-  base::WeakPtrFactory<CredentialManagerDispatcher> weak_factory_;
+  mojo::BindingSet<mojom::CredentialManager> bindings_;
 
-  DISALLOW_COPY_AND_ASSIGN(CredentialManagerDispatcher);
+  base::WeakPtrFactory<CredentialManagerImpl> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(CredentialManagerImpl);
 };
 
 }  // namespace password_manager
 
-#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_DISPATCHER_H_
+#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_BROWSER_CONTENT_CREDENTIAL_MANAGER_IMPL_H_
diff --git a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
similarity index 70%
rename from components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
rename to components/password_manager/content/browser/credential_manager_impl_unittest.cc
index 75a26f1..4286c6e8 100644
--- a/components/password_manager/content/browser/credential_manager_dispatcher_unittest.cc
+++ b/components/password_manager/content/browser/credential_manager_impl_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "components/password_manager/content/browser/credential_manager_dispatcher.h"
+#include "components/password_manager/content/browser/credential_manager_impl.h"
 
 #include <stdint.h>
 
@@ -18,7 +18,7 @@
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/thread_task_runner_handle.h"
-#include "components/password_manager/content/common/credential_manager_messages.h"
+#include "components/password_manager/content/public/cpp/type_converters.h"
 #include "components/password_manager/core/browser/credential_manager_password_form_manager.h"
 #include "components/password_manager/core/browser/mock_affiliated_match_helper.h"
 #include "components/password_manager/core/browser/password_manager.h"
@@ -32,6 +32,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_renderer_host.h"
+#include "mojo/common/url_type_converters.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -44,9 +45,6 @@
 
 namespace {
 
-// Chosen by fair dice roll. Guaranteed to be random.
-const int kRequestId = 4;
-
 const char kTestWebOrigin[] = "https://example.com/";
 const char kTestAndroidRealm1[] = "android://hash@com.example.one.android/";
 const char kTestAndroidRealm2[] = "android://hash@com.example.two.android/";
@@ -135,11 +133,11 @@
   DISALLOW_COPY_AND_ASSIGN(MockPasswordManagerClient);
 };
 
-class TestCredentialManagerDispatcher : public CredentialManagerDispatcher {
+class TestCredentialManagerImpl : public CredentialManagerImpl {
  public:
-  TestCredentialManagerDispatcher(content::WebContents* web_contents,
-                                  PasswordManagerClient* client,
-                                  PasswordManagerDriver* driver);
+  TestCredentialManagerImpl(content::WebContents* web_contents,
+                            PasswordManagerClient* client,
+                            PasswordManagerDriver* driver);
 
  private:
   base::WeakPtr<PasswordManagerDriver> GetDriver() override;
@@ -147,15 +145,14 @@
   base::WeakPtr<PasswordManagerDriver> driver_;
 };
 
-TestCredentialManagerDispatcher::TestCredentialManagerDispatcher(
+TestCredentialManagerImpl::TestCredentialManagerImpl(
     content::WebContents* web_contents,
     PasswordManagerClient* client,
     PasswordManagerDriver* driver)
-    : CredentialManagerDispatcher(web_contents, client),
+    : CredentialManagerImpl(web_contents, client),
       driver_(driver->AsWeakPtr()) {}
 
-base::WeakPtr<PasswordManagerDriver>
-TestCredentialManagerDispatcher::GetDriver() {
+base::WeakPtr<PasswordManagerDriver> TestCredentialManagerImpl::GetDriver() {
   return driver_;
 }
 
@@ -179,12 +176,26 @@
   PasswordManager password_manager_;
 };
 
+// Callbacks from CredentialManagerImpl methods
+void RespondCallback(bool* called) {
+  *called = true;
+}
+
+void GetCredentialCallback(bool* called,
+                           mojom::CredentialManagerError* out_error,
+                           mojom::CredentialInfoPtr* out_info,
+                           mojom::CredentialManagerError error,
+                           mojom::CredentialInfoPtr info) {
+  *called = true;
+  *out_error = error;
+  *out_info = std::move(info);
+}
+
 }  // namespace
 
-class CredentialManagerDispatcherTest
-    : public content::RenderViewHostTestHarness {
+class CredentialManagerImplTest : public content::RenderViewHostTestHarness {
  public:
-  CredentialManagerDispatcherTest() {}
+  CredentialManagerImplTest() {}
 
   void SetUp() override {
     content::RenderViewHostTestHarness::SetUp();
@@ -193,7 +204,7 @@
         new testing::NiceMock<MockPasswordManagerClient>(store_.get()));
     stub_driver_.reset(
         new SlightlyLessStubbyPasswordManagerDriver(client_.get()));
-    dispatcher_.reset(new TestCredentialManagerDispatcher(
+    cm_service_impl_.reset(new TestCredentialManagerImpl(
         web_contents(), client_.get(), stub_driver_.get()));
     ON_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
         .WillByDefault(testing::Return(true));
@@ -251,11 +262,20 @@
   }
 
   void TearDown() override {
+    cm_service_impl_.reset();
+
     store_->ShutdownOnUIThread();
     content::RenderViewHostTestHarness::TearDown();
   }
 
-  void ExpectZeroClickSignInFailure() {
+  void ExpectZeroClickSignInFailure(bool zero_click_only,
+                                    bool include_passwords,
+                                    const std::vector<GURL>& federations) {
+    bool called = false;
+    mojom::CredentialManagerError error;
+    mojom::CredentialInfoPtr credential;
+    CallGet(zero_click_only, include_passwords, federations,
+            base::Bind(&GetCredentialCallback, &called, &error, &credential));
     EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
         .Times(testing::Exactly(0));
     EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_))
@@ -263,18 +283,20 @@
 
     RunAllPendingTasks();
 
-    const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-    const IPC::Message* message =
-        process()->sink().GetFirstMessageMatching(kMsgID);
-    ASSERT_TRUE(message);
-    CredentialManagerMsg_SendCredential::Param send_param;
-    CredentialManagerMsg_SendCredential::Read(message, &send_param);
-
-    EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY,
-              std::get<1>(send_param).type);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+    EXPECT_EQ(mojom::CredentialType::EMPTY, credential->type);
   }
 
-  void ExpectZeroClickSignInSuccess(CredentialType type) {
+  void ExpectZeroClickSignInSuccess(bool zero_click_only,
+                                    bool include_passwords,
+                                    const std::vector<GURL>& federations,
+                                    mojom::CredentialType type) {
+    bool called = false;
+    mojom::CredentialManagerError error;
+    mojom::CredentialInfoPtr credential;
+    CallGet(zero_click_only, include_passwords, federations,
+            base::Bind(&GetCredentialCallback, &called, &error, &credential));
     EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
         .Times(testing::Exactly(0));
     EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_))
@@ -282,17 +304,50 @@
 
     RunAllPendingTasks();
 
-    const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-    const IPC::Message* message =
-        process()->sink().GetFirstMessageMatching(kMsgID);
-    ASSERT_TRUE(message);
-    CredentialManagerMsg_SendCredential::Param send_param;
-    CredentialManagerMsg_SendCredential::Read(message, &send_param);
-
-    EXPECT_EQ(type, std::get<1>(send_param).type);
+    EXPECT_TRUE(called);
+    EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+    EXPECT_EQ(type, credential->type);
   }
 
-  CredentialManagerDispatcher* dispatcher() { return dispatcher_.get(); }
+  void ExpectCredentialType(bool zero_click_only,
+                            bool include_passwords,
+                            const std::vector<GURL>& federations,
+                            mojom::CredentialType type) {
+    bool called = false;
+    mojom::CredentialManagerError error;
+    mojom::CredentialInfoPtr credential;
+    CallGet(zero_click_only, include_passwords, federations,
+            base::Bind(&GetCredentialCallback, &called, &error, &credential));
+
+    RunAllPendingTasks();
+
+    EXPECT_TRUE(called);
+    EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
+    EXPECT_EQ(type, credential->type);
+  }
+
+  CredentialManagerImpl* cm_service_impl() { return cm_service_impl_.get(); }
+
+  // Helpers for testing CredentialManagerImpl methods.
+  void CallStore(const CredentialInfo& info,
+                 const CredentialManagerImpl::StoreCallback& callback) {
+    mojom::CredentialInfoPtr credential = mojom::CredentialInfo::From(info);
+    cm_service_impl_->Store(std::move(credential), callback);
+  }
+
+  void CallRequireUserMediation(
+      const CredentialManagerImpl::RequireUserMediationCallback& callback) {
+    cm_service_impl_->RequireUserMediation(callback);
+  }
+
+  void CallGet(bool zero_click_only,
+               bool include_passwords,
+               const std::vector<GURL>& federations,
+               const CredentialManagerImpl::GetCallback& callback) {
+    cm_service_impl_->Get(zero_click_only, include_passwords,
+                          mojo::Array<mojo::String>::From(federations),
+                          callback);
+  }
 
  protected:
   autofill::PasswordForm form_;
@@ -303,46 +358,42 @@
   scoped_refptr<TestPasswordStore> store_;
   std::unique_ptr<testing::NiceMock<MockPasswordManagerClient>> client_;
   std::unique_ptr<SlightlyLessStubbyPasswordManagerDriver> stub_driver_;
-  std::unique_ptr<CredentialManagerDispatcher> dispatcher_;
+  std::unique_ptr<CredentialManagerImpl> cm_service_impl_;
 };
 
-TEST_F(CredentialManagerDispatcherTest, IsZeroClickAllowed) {
+TEST_F(CredentialManagerImplTest, IsZeroClickAllowed) {
   // IsZeroClickAllowed is uneffected by the first-run status.
   client_->set_zero_click_enabled(true);
   client_->set_first_run_seen(true);
-  EXPECT_TRUE(dispatcher()->IsZeroClickAllowed());
+  EXPECT_TRUE(cm_service_impl()->IsZeroClickAllowed());
 
   client_->set_zero_click_enabled(true);
   client_->set_first_run_seen(false);
-  EXPECT_TRUE(dispatcher()->IsZeroClickAllowed());
+  EXPECT_TRUE(cm_service_impl()->IsZeroClickAllowed());
 
   client_->set_zero_click_enabled(false);
   client_->set_first_run_seen(true);
-  EXPECT_FALSE(dispatcher()->IsZeroClickAllowed());
+  EXPECT_FALSE(cm_service_impl()->IsZeroClickAllowed());
 
   client_->set_zero_click_enabled(false);
   client_->set_first_run_seen(false);
-  EXPECT_FALSE(dispatcher()->IsZeroClickAllowed());
+  EXPECT_FALSE(cm_service_impl()->IsZeroClickAllowed());
 }
 
-TEST_F(CredentialManagerDispatcherTest, CredentialManagerOnStore) {
+TEST_F(CredentialManagerImplTest, CredentialManagerOnStore) {
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
   EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
                             _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(1));
 
-  dispatcher()->OnStore(kRequestId, info);
-
-  const uint32_t kMsgID = CredentialManagerMsg_AcknowledgeStore::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  process()->sink().ClearMessages();
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
 
   // Allow the PasswordFormManager to talk to the password store, determine
   // that the form is new, and set it as pending.
   RunAllPendingTasks();
 
+  EXPECT_TRUE(called);
   EXPECT_TRUE(client_->pending_manager()->HasCompletedMatching());
 
   autofill::PasswordForm new_form =
@@ -355,31 +406,28 @@
   EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, new_form.scheme);
 }
 
-TEST_F(CredentialManagerDispatcherTest, CredentialManagerStoreOverwrite) {
+TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwrite) {
   // Populate the PasswordStore with a form.
   store_->AddLogin(form_);
   RunAllPendingTasks();
 
-  // Calling 'OnStore' with a credential that matches |form_| should update
+  // Calling 'Store' with a credential that matches |form_| should update
   // the password without prompting the user.
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
   info.password = base::ASCIIToUTF16("Totally new password.");
-  dispatcher()->OnStore(kRequestId, info);
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
 
   EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
                             _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(0));
 
-  const uint32_t kMsgID = CredentialManagerMsg_AcknowledgeStore::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  process()->sink().ClearMessages();
-
   // Allow the PasswordFormManager to talk to the password store, determine
   // the form is a match for an existing form, and update the PasswordStore.
   RunAllPendingTasks();
 
+  EXPECT_TRUE(called);
+
   TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
   EXPECT_EQ(1U, passwords.size());
   EXPECT_EQ(1U, passwords[form_.signon_realm].size());
@@ -387,8 +435,7 @@
             passwords[form_.signon_realm][0].password_value);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
-       CredentialManagerStoreOverwriteZeroClick) {
+TEST_F(CredentialManagerImplTest, CredentialManagerStoreOverwriteZeroClick) {
   // Set the global zero click flag on, and populate the PasswordStore with a
   // form that's set to skip zero click.
   client_->set_zero_click_enabled(true);
@@ -397,11 +444,11 @@
   store_->AddLogin(form_);
   RunAllPendingTasks();
 
-  // Calling 'OnStore' with a credential that matches |form_| should update
+  // Calling 'Store' with a credential that matches |form_| should update
   // the credential without prompting the user.
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
-  dispatcher()->OnStore(kRequestId, info);
-  process()->sink().ClearMessages();
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
 
   // Allow the PasswordFormManager to talk to the password store, determine
   // the form is a match for an existing form, and update the PasswordStore.
@@ -412,7 +459,7 @@
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerFederatedStoreOverwriteZeroClick) {
   // Set the global zero click flag on, and populate the PasswordStore with a
   // form that's set to skip zero click.
@@ -424,11 +471,11 @@
   store_->AddLogin(form_);
   RunAllPendingTasks();
 
-  // Calling 'OnStore' with a credential that matches |form_| should update
+  // Calling 'Store' with a credential that matches |form_| should update
   // the credential without prompting the user.
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_FEDERATED);
-  dispatcher()->OnStore(kRequestId, info);
-  process()->sink().ClearMessages();
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
 
   // Allow the PasswordFormManager to talk to the password store, determine
   // the form is a match for an existing form, and update the PasswordStore.
@@ -439,8 +486,7 @@
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
-       CredentialManagerGetOverwriteZeroClick) {
+TEST_F(CredentialManagerImplTest, CredentialManagerGetOverwriteZeroClick) {
   // Set the global zero click flag on, and populate the PasswordStore with a
   // form that's set to skip zero click and has a primary key that won't match
   // credentials initially created via `store()`.
@@ -458,21 +504,23 @@
       .Times(testing::Exactly(1));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
+  bool called = false;
+  mojom::CredentialManagerError error;
+  mojom::CredentialInfoPtr credential;
+  CallGet(false, true, federations,
+          base::Bind(&GetCredentialCallback, &called, &error, &credential));
 
   RunAllPendingTasks();
 
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
+  EXPECT_TRUE(called);
+  EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
 
   // Verify that the update toggled the skip_zero_click flag.
   TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerSignInWithSavingDisabledForCurrentPage) {
   CredentialInfo info(form_, CredentialType::CREDENTIAL_TYPE_PASSWORD);
   EXPECT_CALL(*client_, IsSavingAndFillingEnabledForCurrentPage())
@@ -481,21 +529,16 @@
                             _, CredentialSourceType::CREDENTIAL_SOURCE_API))
       .Times(testing::Exactly(0));
 
-  dispatcher()->OnStore(kRequestId, info);
-
-  const uint32_t kMsgID = CredentialManagerMsg_AcknowledgeStore::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  process()->sink().ClearMessages();
+  bool called = false;
+  CallStore(info, base::Bind(&RespondCallback, &called));
 
   RunAllPendingTasks();
 
+  EXPECT_TRUE(called);
   EXPECT_FALSE(client_->pending_manager());
 }
 
-TEST_F(CredentialManagerDispatcherTest,
-       CredentialManagerOnRequireUserMediation) {
+TEST_F(CredentialManagerImplTest, CredentialManagerOnRequireUserMediation) {
   store_->AddLogin(form_);
   store_->AddLogin(cross_origin_form_);
   RunAllPendingTasks();
@@ -507,15 +550,12 @@
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
   EXPECT_FALSE(passwords[cross_origin_form_.signon_realm][0].skip_zero_click);
 
-  dispatcher()->OnRequireUserMediation(kRequestId);
+  bool called = false;
+  CallRequireUserMediation(base::Bind(&RespondCallback, &called));
+
   RunAllPendingTasks();
 
-  const uint32_t kMsgID =
-      CredentialManagerMsg_AcknowledgeRequireUserMediation::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  process()->sink().ClearMessages();
+  EXPECT_TRUE(called);
 
   passwords = store_->stored_passwords();
   EXPECT_EQ(2U, passwords.size());
@@ -525,7 +565,7 @@
   EXPECT_FALSE(passwords[cross_origin_form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequireUserMediationIncognito) {
   EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
   store_->AddLogin(form_);
@@ -536,15 +576,11 @@
   ASSERT_EQ(1U, passwords[form_.signon_realm].size());
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
 
-  dispatcher()->OnRequireUserMediation(kRequestId);
+  bool called = false;
+  CallRequireUserMediation(base::Bind(&RespondCallback, &called));
   RunAllPendingTasks();
 
-  const uint32_t kMsgID =
-      CredentialManagerMsg_AcknowledgeRequireUserMediation::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  process()->sink().ClearMessages();
+  EXPECT_TRUE(called);
 
   passwords = store_->stored_passwords();
   ASSERT_EQ(1U, passwords.size());
@@ -552,7 +588,7 @@
   EXPECT_FALSE(passwords[form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequireUserMediationWithAffiliation) {
   store_->AddLogin(form_);
   store_->AddLogin(cross_origin_form_);
@@ -567,7 +603,7 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
   RunAllPendingTasks();
 
   TestPasswordStore::PasswordMap passwords = store_->stored_passwords();
@@ -577,9 +613,9 @@
   EXPECT_FALSE(passwords[affiliated_form1_.signon_realm][0].skip_zero_click);
   EXPECT_FALSE(passwords[affiliated_form2_.signon_realm][0].skip_zero_click);
 
-  dispatcher()->OnRequireUserMediation(kRequestId);
+  bool called = false;
+  CallRequireUserMediation(base::Bind(&RespondCallback, &called));
   RunAllPendingTasks();
-  process()->sink().ClearMessages();
 
   passwords = store_->stored_passwords();
   EXPECT_EQ(4U, passwords.size());
@@ -589,7 +625,7 @@
   EXPECT_FALSE(passwords[affiliated_form2_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithEmptyPasswordStore) {
   std::vector<GURL> federations;
   EXPECT_CALL(*client_, PromptUserToSavePasswordPtr(
@@ -599,21 +635,10 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param param;
-  CredentialManagerMsg_SendCredential::Read(message, &param);
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY, std::get<1>(param).type);
-  process()->sink().ClearMessages();
+  ExpectCredentialType(false, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithCrossOriginPasswordStore) {
   store_->AddLogin(cross_origin_form_);
 
@@ -625,21 +650,10 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param param;
-  CredentialManagerMsg_SendCredential::Read(message, &param);
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY, std::get<1>(param).type);
-  process()->sink().ClearMessages();
+  ExpectCredentialType(false, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithFullPasswordStore) {
   client_->set_zero_click_enabled(false);
   store_->AddLogin(form_);
@@ -649,39 +663,39 @@
       .Times(testing::Exactly(1));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
+  bool called = false;
+  mojom::CredentialManagerError error;
+  mojom::CredentialInfoPtr credential;
+  CallGet(false, true, federations,
+          base::Bind(&GetCredentialCallback, &called, &error, &credential));
 
   RunAllPendingTasks();
 
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
+  EXPECT_TRUE(called);
+  EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
 }
 
 TEST_F(
-    CredentialManagerDispatcherTest,
+    CredentialManagerImplTest,
     CredentialManagerOnRequestCredentialWithZeroClickOnlyEmptyPasswordStore) {
   std::vector<GURL> federations;
   EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
+  bool called = false;
+  mojom::CredentialManagerError error;
+  mojom::CredentialInfoPtr credential;
+  CallGet(true, true, federations,
+          base::Bind(&GetCredentialCallback, &called, &error, &credential));
 
   RunAllPendingTasks();
 
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param send_param;
-  CredentialManagerMsg_SendCredential::Read(message, &send_param);
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY,
-            std::get<1>(send_param).type);
+  EXPECT_TRUE(called);
+  EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithZeroClickOnlyFullPasswordStore) {
   store_->AddLogin(form_);
   client_->set_first_run_seen(true);
@@ -689,12 +703,12 @@
   std::vector<GURL> federations;
 
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::PASSWORD);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithoutPasswords) {
   store_->AddLogin(form_);
   client_->set_first_run_seen(true);
@@ -702,12 +716,11 @@
   std::vector<GURL> federations;
 
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
-  dispatcher()->OnRequestCredential(kRequestId, true, false, federations);
 
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, false, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialFederatedMatch) {
   form_.federation_origin = url::Origin(GURL("https://example.com/"));
   store_->AddLogin(form_);
@@ -717,12 +730,12 @@
   federations.push_back(GURL("https://example.com/"));
 
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_FEDERATED);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::FEDERATED);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialFederatedNoMatch) {
   form_.federation_origin = url::Origin(GURL("https://example.com/"));
   store_->AddLogin(form_);
@@ -732,12 +745,11 @@
   federations.push_back(GURL("https://not-example.com/"));
 
   EXPECT_CALL(*client_, NotifyUserCouldBeAutoSignedInPtr(_)).Times(0);
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialAffiliatedPasswordMatch) {
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
@@ -749,16 +761,15 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
   // We pass in 'true' for the 'include_passwords' argument to ensure that
   // password-type credentials are included as potential matches.
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::PASSWORD);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialAffiliatedPasswordNoMatch) {
   store_->AddLogin(affiliated_form1_);
   client_->set_first_run_seen(true);
@@ -770,16 +781,14 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
   // We pass in 'false' for the 'include_passwords' argument to ensure that
   // password-type credentials are excluded as potential matches.
-  dispatcher()->OnRequestCredential(kRequestId, true, false, federations);
-
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, false, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialAffiliatedFederatedMatch) {
   affiliated_form1_.federation_origin =
       url::Origin(GURL("https://example.com/"));
@@ -795,14 +804,13 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_FEDERATED);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::FEDERATED);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialAffiliatedFederatedNoMatch) {
   affiliated_form1_.federation_origin =
       url::Origin(GURL("https://example.com/"));
@@ -818,14 +826,12 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest, RequestCredentialWithoutFirstRun) {
+TEST_F(CredentialManagerImplTest, RequestCredentialWithoutFirstRun) {
   client_->set_first_run_seen(false);
 
   store_->AddLogin(form_);
@@ -834,12 +840,11 @@
   EXPECT_CALL(*client_,
               NotifyUserCouldBeAutoSignedInPtr(testing::Pointee(form_)))
       .Times(1);
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest, RequestCredentialWithFirstRunAndSkip) {
+TEST_F(CredentialManagerImplTest, RequestCredentialWithFirstRunAndSkip) {
   client_->set_first_run_seen(true);
 
   form_.skip_zero_click = true;
@@ -849,12 +854,11 @@
   EXPECT_CALL(*client_,
               NotifyUserCouldBeAutoSignedInPtr(testing::Pointee(form_)))
       .Times(1);
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest, RequestCredentialWithTLSErrors) {
+TEST_F(CredentialManagerImplTest, RequestCredentialWithTLSErrors) {
   // If we encounter TLS errors, we won't return credentials.
   EXPECT_CALL(*client_, DidLastPageLoadEncounterSSLErrors())
       .WillRepeatedly(testing::Return(true));
@@ -862,12 +866,11 @@
   store_->AddLogin(form_);
 
   std::vector<GURL> federations;
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
 
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWithZeroClickOnlyTwoPasswordStore) {
   store_->AddLogin(form_);
   store_->AddLogin(origin_path_form_);
@@ -877,23 +880,11 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param send_param;
-  CredentialManagerMsg_SendCredential::Read(message, &send_param);
-
   // With two items in the password store, we shouldn't get credentials back.
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY,
-            std::get<1>(send_param).type);
+  ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        OnRequestCredentialWithZeroClickOnlyAndSkipZeroClickPasswordStore) {
   form_.skip_zero_click = true;
   store_->AddLogin(form_);
@@ -904,24 +895,12 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param send_param;
-  CredentialManagerMsg_SendCredential::Read(message, &send_param);
-
   // With two items in the password store, we shouldn't get credentials back,
   // even though only one item has |skip_zero_click| set |false|.
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY,
-            std::get<1>(send_param).type);
+  ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        OnRequestCredentialWithZeroClickOnlyCrossOriginPasswordStore) {
   store_->AddLogin(cross_origin_form_);
 
@@ -933,24 +912,12 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param send_param;
-  CredentialManagerMsg_SendCredential::Read(message, &send_param);
-
   // We only have cross-origin zero-click credentials; they should not be
   // returned.
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY,
-            std::get<1>(send_param).type);
+  ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        CredentialManagerOnRequestCredentialWhileRequestPending) {
   client_->set_zero_click_enabled(false);
   store_->AddLogin(form_);
@@ -960,40 +927,40 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
-  dispatcher()->OnRequestCredential(kRequestId + 1, false, true, federations);
+  // 1st request.
+  bool called_1 = false;
+  mojom::CredentialManagerError error_1;
+  mojom::CredentialInfoPtr credential_1;
+  CallGet(
+      false, true, federations,
+      base::Bind(&GetCredentialCallback, &called_1, &error_1, &credential_1));
+  // 2nd request.
+  bool called_2 = false;
+  mojom::CredentialManagerError error_2;
+  mojom::CredentialInfoPtr credential_2;
+  CallGet(
+      false, true, federations,
+      base::Bind(&GetCredentialCallback, &called_2, &error_2, &credential_2));
 
-  // Check that the second request triggered a rejection.
-  uint32_t kMsgID = CredentialManagerMsg_RejectCredentialRequest::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-
-  CredentialManagerMsg_RejectCredentialRequest::Param reject_param;
-  CredentialManagerMsg_RejectCredentialRequest::Read(message, &reject_param);
-  EXPECT_EQ(blink::WebCredentialManagerPendingRequestError,
-            std::get<1>(reject_param));
   EXPECT_CALL(*client_, PromptUserToChooseCredentialsPtr(_, _, _, _))
       .Times(testing::Exactly(1));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  process()->sink().ClearMessages();
-
   // Execute the PasswordStore asynchronousness.
   RunAllPendingTasks();
 
+  // Check that the second request triggered a rejection.
+  EXPECT_TRUE(called_2);
+  EXPECT_EQ(mojom::CredentialManagerError::PENDINGREQUEST, error_2);
+  EXPECT_TRUE(credential_2.is_null());
+
   // Check that the first request resolves.
-  kMsgID = CredentialManagerMsg_SendCredential::ID;
-  message = process()->sink().GetFirstMessageMatching(kMsgID);
-  EXPECT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param send_param;
-  CredentialManagerMsg_SendCredential::Read(message, &send_param);
-  EXPECT_NE(CredentialType::CREDENTIAL_TYPE_EMPTY,
-            std::get<1>(send_param).type);
-  process()->sink().ClearMessages();
+  EXPECT_TRUE(called_1);
+  EXPECT_EQ(mojom::CredentialManagerError::SUCCESS, error_1);
+  EXPECT_NE(mojom::CredentialType::EMPTY, credential_1->type);
 }
 
-TEST_F(CredentialManagerDispatcherTest, ResetSkipZeroClickAfterPrompt) {
+TEST_F(CredentialManagerImplTest, ResetSkipZeroClickAfterPrompt) {
   // Turn on the global zero-click flag, and add two credentials in separate
   // origins, both set to skip zero-click.
   client_->set_zero_click_enabled(true);
@@ -1026,7 +993,12 @@
       .Times(testing::Exactly(1));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true, federations);
+  bool called = false;
+  mojom::CredentialManagerError error;
+  mojom::CredentialInfoPtr credential;
+  CallGet(false, true, federations,
+          base::Bind(&GetCredentialCallback, &called, &error, &credential));
+
   RunAllPendingTasks();
 
   passwords = store_->stored_passwords();
@@ -1037,8 +1009,7 @@
   EXPECT_TRUE(passwords[cross_origin_form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
-       NoResetSkipZeroClickAfterPromptInIncognito) {
+TEST_F(CredentialManagerImplTest, NoResetSkipZeroClickAfterPromptInIncognito) {
   EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
   // Turn on the global zero-click flag which should be overriden by Incognito.
   client_->set_zero_click_enabled(true);
@@ -1058,8 +1029,12 @@
       .Times(testing::Exactly(1));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, false, true,
-                                    std::vector<GURL>());
+  bool called = false;
+  mojom::CredentialManagerError error;
+  mojom::CredentialInfoPtr credential;
+  CallGet(false, true, std::vector<GURL>(),
+          base::Bind(&GetCredentialCallback, &called, &error, &credential));
+
   RunAllPendingTasks();
 
   // The form shouldn't become a zero-click one.
@@ -1069,7 +1044,7 @@
   EXPECT_TRUE(passwords[form_.signon_realm][0].skip_zero_click);
 }
 
-TEST_F(CredentialManagerDispatcherTest, IncognitoZeroClickRequestCredential) {
+TEST_F(CredentialManagerImplTest, IncognitoZeroClickRequestCredential) {
   EXPECT_CALL(*client_, IsOffTheRecord()).WillRepeatedly(testing::Return(true));
   store_->AddLogin(form_);
 
@@ -1078,21 +1053,10 @@
       .Times(testing::Exactly(0));
   EXPECT_CALL(*client_, NotifyUserAutoSigninPtr(_)).Times(testing::Exactly(0));
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  RunAllPendingTasks();
-
-  const uint32_t kMsgID = CredentialManagerMsg_SendCredential::ID;
-  const IPC::Message* message =
-      process()->sink().GetFirstMessageMatching(kMsgID);
-  ASSERT_TRUE(message);
-  CredentialManagerMsg_SendCredential::Param param;
-  CredentialManagerMsg_SendCredential::Read(message, &param);
-  EXPECT_EQ(CredentialType::CREDENTIAL_TYPE_EMPTY, std::get<1>(param).type);
+  ExpectCredentialType(true, true, federations, mojom::CredentialType::EMPTY);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
-       ZeroClickWithAffiliatedFormInPasswordStore) {
+TEST_F(CredentialManagerImplTest, ZeroClickWithAffiliatedFormInPasswordStore) {
   // Insert the affiliated form into the store, and mock out the association
   // with the current origin. As it's the only form matching the origin, it
   // ought to be returned automagically.
@@ -1106,14 +1070,13 @@
   affiliated_realms.push_back(kTestAndroidRealm1);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::PASSWORD);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        ZeroClickWithTwoAffiliatedFormsInPasswordStore) {
   // Insert two affiliated forms into the store, and mock out the association
   // with the current origin. Multiple forms === no zero-click sign in.
@@ -1129,14 +1092,12 @@
   affiliated_realms.push_back(kTestAndroidRealm2);
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        ZeroClickWithUnaffiliatedFormsInPasswordStore) {
   // Insert the affiliated form into the store, but don't mock out the
   // association with the current origin. No association === no zero-click sign
@@ -1150,14 +1111,12 @@
   std::vector<std::string> affiliated_realms;
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInFailure();
+  ExpectZeroClickSignInFailure(true, true, federations);
 }
 
-TEST_F(CredentialManagerDispatcherTest,
+TEST_F(CredentialManagerImplTest,
        ZeroClickWithFormAndUnaffiliatedFormsInPasswordStore) {
   // Insert the affiliated form into the store, along with a real form for the
   // origin, and don't mock out the association with the current origin. No
@@ -1172,16 +1131,15 @@
   std::vector<std::string> affiliated_realms;
   static_cast<MockAffiliatedMatchHelper*>(store_->affiliated_match_helper())
       ->ExpectCallToGetAffiliatedAndroidRealms(
-          dispatcher_->GetSynthesizedFormForOrigin(), affiliated_realms);
+          cm_service_impl_->GetSynthesizedFormForOrigin(), affiliated_realms);
 
-  dispatcher()->OnRequestCredential(kRequestId, true, true, federations);
-
-  ExpectZeroClickSignInSuccess(CredentialType::CREDENTIAL_TYPE_PASSWORD);
+  ExpectZeroClickSignInSuccess(true, true, federations,
+                               mojom::CredentialType::PASSWORD);
 }
 
-TEST_F(CredentialManagerDispatcherTest, GetSynthesizedFormForOrigin) {
+TEST_F(CredentialManagerImplTest, GetSynthesizedFormForOrigin) {
   autofill::PasswordForm synthesized =
-      dispatcher_->GetSynthesizedFormForOrigin();
+      cm_service_impl_->GetSynthesizedFormForOrigin();
   EXPECT_EQ(kTestWebOrigin, synthesized.origin.spec());
   EXPECT_EQ(kTestWebOrigin, synthesized.signon_realm);
   EXPECT_EQ(autofill::PasswordForm::SCHEME_HTML, synthesized.scheme);
diff --git a/components/password_manager/content/common/BUILD.gn b/components/password_manager/content/common/BUILD.gn
deleted file mode 100644
index 3fb2464..0000000
--- a/components/password_manager/content/common/BUILD.gn
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-static_library("common") {
-  sources = [
-    "credential_manager_content_utils.cc",
-    "credential_manager_content_utils.h",
-    "credential_manager_message_generator.cc",
-    "credential_manager_message_generator.h",
-    "credential_manager_messages.h",
-  ]
-
-  deps = [
-    "//base",
-    "//components/password_manager/core/common",
-    "//content/public/common",
-    "//ipc",
-    "//third_party/WebKit/public:blink_headers",
-    "//url",
-  ]
-}
diff --git a/components/password_manager/content/common/DEPS b/components/password_manager/content/common/DEPS
deleted file mode 100644
index c3505fa..0000000
--- a/components/password_manager/content/common/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+content/public/common",
-  "+ipc",
-]
diff --git a/components/password_manager/content/common/OWNERS b/components/password_manager/content/common/OWNERS
deleted file mode 100644
index 790e6d7..0000000
--- a/components/password_manager/content/common/OWNERS
+++ /dev/null
@@ -1,13 +0,0 @@
-# Changes to IPC messages require a security review to avoid introducing
-# new sandbox escapes.
-per-file credential_manager_messages*.h=set noparent
-per-file credential_manager_messages*.h=dcheng@chromium.org
-per-file credential_manager_messages*.h=inferno@chromium.org
-per-file credential_manager_messages*.h=jln@chromium.org
-per-file credential_manager_messages*.h=jschuh@chromium.org
-per-file credential_manager_messages*.h=kenrb@chromium.org
-per-file credential_manager_messages*.h=mkwst@chromium.org
-per-file credential_manager_messages*.h=nasko@chromium.org
-per-file credential_manager_messages*.h=palmer@chromium.org
-per-file credential_manager_messages*.h=tsepez@chromium.org
-per-file credential_manager_messages*.h=wfh@chromium.org
diff --git a/components/password_manager/content/common/credential_manager_content_utils.cc b/components/password_manager/content/common/credential_manager_content_utils.cc
deleted file mode 100644
index 6205abd..0000000
--- a/components/password_manager/content/common/credential_manager_content_utils.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "components/password_manager/content/common/credential_manager_content_utils.h"
-
-#include "base/logging.h"
-#include "third_party/WebKit/public/platform/WebCredential.h"
-#include "third_party/WebKit/public/platform/WebFederatedCredential.h"
-#include "third_party/WebKit/public/platform/WebPasswordCredential.h"
-
-namespace password_manager {
-
-CredentialInfo WebCredentialToCredentialInfo(
-    const blink::WebCredential& credential) {
-  CredentialInfo credential_info;
-  credential_info.id = credential.id();
-  credential_info.name = credential.name();
-  credential_info.icon = credential.iconURL();
-  credential_info.type = credential.isPasswordCredential()
-                             ? CredentialType::CREDENTIAL_TYPE_PASSWORD
-                             : CredentialType::CREDENTIAL_TYPE_FEDERATED;
-  if (credential_info.type == CredentialType::CREDENTIAL_TYPE_PASSWORD) {
-    DCHECK(credential.isPasswordCredential());
-    credential_info.password =
-        static_cast<const blink::WebPasswordCredential&>(credential).password();
-  } else {
-    DCHECK(credential.isFederatedCredential());
-    credential_info.federation =
-        static_cast<const blink::WebFederatedCredential&>(credential)
-            .provider();
-  }
-  return credential_info;
-}
-
-}  // namespace password_manager
diff --git a/components/password_manager/content/common/credential_manager_content_utils.h b/components/password_manager/content/common/credential_manager_content_utils.h
deleted file mode 100644
index 77315f7..0000000
--- a/components/password_manager/content/common/credential_manager_content_utils.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_CONTENT_UTILS_H_
-#define COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_CONTENT_UTILS_H_
-
-#include "components/password_manager/core/common/credential_manager_types.h"
-
-namespace blink {
-class WebCredential;
-};
-
-namespace password_manager {
-
-// Returns a CredentialInfo struct populated from |credential|.
-CredentialInfo WebCredentialToCredentialInfo(
-    const blink::WebCredential& credential);
-
-}  // namespace password_manager
-
-#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_COMMON_CREDENTIAL_MANAGER_CONTENT_UTILS_H_
diff --git a/components/password_manager/content/common/credential_manager_message_generator.cc b/components/password_manager/content/common/credential_manager_message_generator.cc
deleted file mode 100644
index 55eaf88..0000000
--- a/components/password_manager/content/common/credential_manager_message_generator.cc
+++ /dev/null
@@ -1,33 +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.
-
-// Get basic type definitions.
-#define IPC_MESSAGE_IMPL
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-
-// Generate constructors.
-#include "ipc/struct_constructor_macros.h"
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-
-// Generate destructors.
-#include "ipc/struct_destructor_macros.h"
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-
-// Generate param traits write methods.
-#include "ipc/param_traits_write_macros.h"
-namespace IPC {
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-}  // namespace IPC
-
-// Generate param traits read methods.
-#include "ipc/param_traits_read_macros.h"
-namespace IPC {
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-}  // namespace IPC
-
-// Generate param traits log methods.
-#include "ipc/param_traits_log_macros.h"
-namespace IPC {
-#include "components/password_manager/content/common/credential_manager_message_generator.h"
-}  // namespace IPC
diff --git a/components/password_manager/content/common/credential_manager_message_generator.h b/components/password_manager/content/common/credential_manager_message_generator.h
deleted file mode 100644
index c818a138..0000000
--- a/components/password_manager/content/common/credential_manager_message_generator.h
+++ /dev/null
@@ -1,7 +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.
-
-// Multiply-included file, hence no include guard.
-
-#include "components/password_manager/content/common/credential_manager_messages.h"
diff --git a/components/password_manager/content/common/credential_manager_messages.h b/components/password_manager/content/common/credential_manager_messages.h
deleted file mode 100644
index 6ac642f..0000000
--- a/components/password_manager/content/common/credential_manager_messages.h
+++ /dev/null
@@ -1,86 +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.
-
-// Message definition file, included multiple times, hence no include guard.
-
-#include <string>
-#include <vector>
-
-#include "base/strings/string16.h"
-#include "components/password_manager/core/common/credential_manager_types.h"
-#include "content/public/common/common_param_traits.h"
-#include "ipc/ipc_message_macros.h"
-#include "ipc/ipc_message_utils.h"
-#include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
-#include "url/gurl.h"
-#include "url/ipc/url_param_traits.h"
-
-#define IPC_MESSAGE_START CredentialManagerMsgStart
-
-IPC_ENUM_TRAITS_MAX_VALUE(
-    password_manager::CredentialType,
-    password_manager::CredentialType::CREDENTIAL_TYPE_LAST)
-
-IPC_ENUM_TRAITS_MAX_VALUE(blink::WebCredentialManagerError,
-                          blink::WebCredentialManagerErrorLastType)
-
-IPC_STRUCT_TRAITS_BEGIN(password_manager::CredentialInfo)
-  IPC_STRUCT_TRAITS_MEMBER(type)
-  IPC_STRUCT_TRAITS_MEMBER(id)
-  IPC_STRUCT_TRAITS_MEMBER(name)
-  IPC_STRUCT_TRAITS_MEMBER(icon)
-  IPC_STRUCT_TRAITS_MEMBER(password)
-  IPC_STRUCT_TRAITS_MEMBER(federation)
-IPC_STRUCT_TRAITS_END()
-
-// ----------------------------------------------------------------------------
-// Messages sent from the renderer to the browser
-
-// Passes the notification from 'navigator.credentials.store()' up to
-// the browser process in order to (among other things) prompt the user to save
-// the credential she used for signin. The browser process will respond with a
-// CredentialManagerMsg_AcknowledgeStore message.
-IPC_MESSAGE_ROUTED2(CredentialManagerHostMsg_Store,
-                    int /* request_id */,
-                    password_manager::CredentialInfo /* credential */)
-
-// Passes the notification from 'navigator.credentials.requireUserMediation()'
-// up to the browser process in order to clear the "zeroclick" bit on that
-// origin's stored credentials. The browser process will respond with a
-// CredentialManagerMsg_AcknowledgeRequireUserMediation message.
-IPC_MESSAGE_ROUTED1(CredentialManagerHostMsg_RequireUserMediation,
-                    int /* request_id */)
-
-// Requests a credential from the browser process in response to a page calling
-// 'navigator.credentials.get()'. The browser process will respond with a
-// CredentialManagerMsg_SendCredential message.
-IPC_MESSAGE_ROUTED4(CredentialManagerHostMsg_RequestCredential,
-                    int /* request_id */,
-                    bool /* zero_click_only */,
-                    bool /* include_passwords */,
-                    std::vector<GURL> /* federations */)
-
-// ----------------------------------------------------------------------------
-// Messages sent from the browser to the renderer
-
-// Notify the renderer that the browser process has finished processing a
-// CredentialManagerHostMsg_Store message.
-IPC_MESSAGE_ROUTED1(CredentialManagerMsg_AcknowledgeStore, int /* request_id */)
-
-// Notify the renderer that the browser process has finished processing a
-// CredentialManagerHostMsg_RequireUserMediation message.
-IPC_MESSAGE_ROUTED1(CredentialManagerMsg_AcknowledgeRequireUserMediation,
-                    int /* request_id */)
-
-// Send a credential to the renderer in response to a
-// CredentialManagerHostMsg_RequestCredential message.
-IPC_MESSAGE_ROUTED2(CredentialManagerMsg_SendCredential,
-                    int /* request_id */,
-                    password_manager::CredentialInfo /* credential */)
-
-// Reject the credential request in response to a
-// CredentialManagerHostMsg_RequestCredential message.
-IPC_MESSAGE_ROUTED2(CredentialManagerMsg_RejectCredentialRequest,
-                    int /* request_id */,
-                    blink::WebCredentialManagerError /* rejection_reason */)
diff --git a/components/password_manager/content/public/cpp/BUILD.gn b/components/password_manager/content/public/cpp/BUILD.gn
new file mode 100644
index 0000000..a4c0353
--- /dev/null
+++ b/components/password_manager/content/public/cpp/BUILD.gn
@@ -0,0 +1,23 @@
+# 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 = [
+    "type_converters.cc",
+    "type_converters.h",
+  ]
+
+  public_deps = [
+    "../interfaces",
+  ]
+
+  deps = [
+    "//base",
+    "//components/password_manager/core/common",
+    "//mojo/common:common_base",
+    "//mojo/common:url_type_converters",
+    "//mojo/public/cpp/bindings",
+    "//third_party/WebKit/public:blink",
+  ]
+}
diff --git a/components/password_manager/content/public/cpp/type_converters.cc b/components/password_manager/content/public/cpp/type_converters.cc
new file mode 100644
index 0000000..6076149
--- /dev/null
+++ b/components/password_manager/content/public/cpp/type_converters.cc
@@ -0,0 +1,128 @@
+// 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/password_manager/content/public/cpp/type_converters.h"
+
+#include "base/logging.h"
+#include "components/password_manager/core/common/credential_manager_types.h"
+#include "mojo/common/common_type_converters.h"
+#include "mojo/common/url_type_converters.h"
+#include "third_party/WebKit/public/platform/WebCredential.h"
+#include "third_party/WebKit/public/platform/WebFederatedCredential.h"
+#include "third_party/WebKit/public/platform/WebPasswordCredential.h"
+
+using namespace password_manager;
+
+namespace mojo {
+
+namespace {
+
+mojom::CredentialType CMCredentialTypeToMojo(CredentialType type) {
+  switch (type) {
+    case CredentialType::CREDENTIAL_TYPE_EMPTY:
+      return mojom::CredentialType::EMPTY;
+    case CredentialType::CREDENTIAL_TYPE_PASSWORD:
+      return mojom::CredentialType::PASSWORD;
+    case CredentialType::CREDENTIAL_TYPE_FEDERATED:
+      return mojom::CredentialType::FEDERATED;
+  }
+
+  NOTREACHED();
+  return mojom::CredentialType::EMPTY;
+}
+
+CredentialType MojoCredentialTypeToCM(mojom::CredentialType type) {
+  switch (type) {
+    case mojom::CredentialType::EMPTY:
+      return CredentialType::CREDENTIAL_TYPE_EMPTY;
+    case mojom::CredentialType::PASSWORD:
+      return CredentialType::CREDENTIAL_TYPE_PASSWORD;
+    case mojom::CredentialType::FEDERATED:
+      return CredentialType::CREDENTIAL_TYPE_FEDERATED;
+  }
+
+  NOTREACHED();
+  return CredentialType::CREDENTIAL_TYPE_EMPTY;
+}
+
+}  // namespace
+
+mojom::CredentialInfoPtr
+TypeConverter<mojom::CredentialInfoPtr, CredentialInfo>::Convert(
+    const CredentialInfo& input) {
+  mojom::CredentialInfoPtr output(mojom::CredentialInfo::New());
+  output->type = CMCredentialTypeToMojo(input.type);
+  output->id = mojo::String::From(input.id);
+  output->name = mojo::String::From(input.name);
+  output->icon = mojo::String::From(input.icon);
+  output->password = mojo::String::From(input.password);
+  output->federation = input.federation;
+
+  return output;
+}
+
+CredentialInfo TypeConverter<CredentialInfo, mojom::CredentialInfoPtr>::Convert(
+    const mojom::CredentialInfoPtr& input) {
+  CredentialInfo output;
+  output.type = MojoCredentialTypeToCM(input->type);
+  output.id = input->id.To<base::string16>();
+  output.name = input->name.To<base::string16>();
+  output.icon = input->icon.To<GURL>();
+  output.password = input->password.To<base::string16>();
+  output.federation = input->federation;
+
+  return output;
+}
+
+mojom::CredentialInfoPtr
+TypeConverter<mojom::CredentialInfoPtr, blink::WebCredential>::Convert(
+    const blink::WebCredential& input) {
+  mojom::CredentialInfoPtr output(mojom::CredentialInfo::New());
+
+  if (input.isPasswordCredential()) {
+    // blink::WebPasswordCredential
+    output->type = mojom::CredentialType::PASSWORD;
+    output->password = mojo::String::From(base::string16(
+        static_cast<const blink::WebPasswordCredential&>(input).password()));
+  } else {
+    DCHECK(input.isFederatedCredential());
+    // blink::WebFederatedCredential
+    output->type = mojom::CredentialType::FEDERATED;
+    output->federation =
+        static_cast<const blink::WebFederatedCredential&>(input).provider();
+  }
+  output->id = mojo::String::From(base::string16(input.id()));
+  output->name = mojo::String::From(base::string16(input.name()));
+  output->icon = mojo::String::From(GURL(input.iconURL()));
+
+  return output;
+}
+
+scoped_ptr<blink::WebCredential> TypeConverter<
+    scoped_ptr<blink::WebCredential>,
+    mojom::CredentialInfoPtr>::Convert(const mojom::CredentialInfoPtr& input) {
+  scoped_ptr<blink::WebCredential> output;
+
+  switch (input->type) {
+    case mojom::CredentialType::PASSWORD:
+      output.reset(new blink::WebPasswordCredential(
+          input->id.To<base::string16>(), input->password.To<base::string16>(),
+          input->name.To<base::string16>(), input->icon.To<GURL>()));
+      break;
+    case mojom::CredentialType::FEDERATED:
+      output.reset(new blink::WebFederatedCredential(
+          input->id.To<base::string16>(), input->federation,
+          input->name.To<base::string16>(), input->icon.To<GURL>()));
+      break;
+    case mojom::CredentialType::EMPTY:
+      // Intentionally empty, return nullptr.
+      break;
+    default:
+      NOTREACHED();
+  }
+
+  return output;
+}
+
+}  // namespace mojo
diff --git a/components/password_manager/content/public/cpp/type_converters.h b/components/password_manager/content/public/cpp/type_converters.h
new file mode 100644
index 0000000..648114f
--- /dev/null
+++ b/components/password_manager/content/public/cpp/type_converters.h
@@ -0,0 +1,51 @@
+// 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_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
+#define COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
+
+namespace blink {
+class WebCredential;
+}
+
+namespace password_manager {
+struct CredentialInfo;
+}
+
+namespace mojo {
+
+template <>
+struct TypeConverter<password_manager::mojom::CredentialInfoPtr,
+                     password_manager::CredentialInfo> {
+  static password_manager::mojom::CredentialInfoPtr Convert(
+      const password_manager::CredentialInfo& input);
+};
+
+template <>
+struct TypeConverter<password_manager::CredentialInfo,
+                     password_manager::mojom::CredentialInfoPtr> {
+  static password_manager::CredentialInfo Convert(
+      const password_manager::mojom::CredentialInfoPtr& input);
+};
+
+template <>
+struct TypeConverter<password_manager::mojom::CredentialInfoPtr,
+                     blink::WebCredential> {
+  static password_manager::mojom::CredentialInfoPtr Convert(
+      const blink::WebCredential& input);
+};
+
+template <>
+struct TypeConverter<scoped_ptr<blink::WebCredential>,
+                     password_manager::mojom::CredentialInfoPtr> {
+  static scoped_ptr<blink::WebCredential> Convert(
+      const password_manager::mojom::CredentialInfoPtr& input);
+};
+
+}  // namespace mojo
+
+#endif  // COMPONENTS_PASSWORD_MANAGER_CONTENT_PUBLIC_CPP_TYPE_CONVERTERS_IMPL_H_
diff --git a/mojo/services/catalog/public/interfaces/BUILD.gn b/components/password_manager/content/public/interfaces/BUILD.gn
similarity index 65%
copy from mojo/services/catalog/public/interfaces/BUILD.gn
copy to components/password_manager/content/public/interfaces/BUILD.gn
index 299b7dd..4c29ae1 100644
--- a/mojo/services/catalog/public/interfaces/BUILD.gn
+++ b/components/password_manager/content/public/interfaces/BUILD.gn
@@ -6,13 +6,12 @@
 
 mojom("interfaces") {
   sources = [
-    "catalog.mojom",
-    "resolver.mojom",
+    "credential_manager.mojom",
   ]
 
-  import_dirs = [ "//mojo/services" ]
+  typemaps = [ "//url/mojo/origin.typemap" ]
 
-  deps = [
-    "//services/shell/public/interfaces",
+  public_deps = [
+    "//url/mojo:url_mojom_origin",
   ]
 }
diff --git a/components/password_manager/content/public/interfaces/OWNERS b/components/password_manager/content/public/interfaces/OWNERS
new file mode 100644
index 0000000..7afd0f9
--- /dev/null
+++ b/components/password_manager/content/public/interfaces/OWNERS
@@ -0,0 +1,13 @@
+# Changes to mojom files require a security review to avoid introducing
+# new sandbox escapes.
+per-file *.mojom=set noparent
+per-file *.mojom=dcheng@chromium.org
+per-file *.mojom=inferno@chromium.org
+per-file *.mojom=jln@chromium.org
+per-file *.mojom=jschuh@chromium.org
+per-file *.mojom=kenrb@chromium.org
+per-file *.mojom=mkwst@chromium.org
+per-file *.mojom=nasko@chromium.org
+per-file *.mojom=palmer@chromium.org
+per-file *.mojom=tsepez@chromium.org
+per-file *.mojom=wfh@chromium.org
diff --git a/components/password_manager/content/public/interfaces/credential_manager.mojom b/components/password_manager/content/public/interfaces/credential_manager.mojom
new file mode 100644
index 0000000..cc9492b
--- /dev/null
+++ b/components/password_manager/content/public/interfaces/credential_manager.mojom
@@ -0,0 +1,44 @@
+// 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.
+
+module password_manager.mojom;
+
+import "url/mojo/origin.mojom";
+
+enum CredentialType {
+  EMPTY,
+  PASSWORD,
+  FEDERATED
+};
+
+enum CredentialManagerError {
+  SUCCESS,
+  DISABLED,
+  PENDINGREQUEST,
+  PASSWORDSTOREUNAVAILABLE,
+  UNKNOWN
+};
+
+struct CredentialInfo {
+  CredentialType type = EMPTY;
+  string id = "";
+  string name = "";
+  string icon = "";
+  string password = "";
+  url.mojom.Origin federation;
+};
+
+interface CredentialManager {
+  // Store credential. For navigator.credentials.store().
+  Store(CredentialInfo credential) => ();
+
+  // Require user mediation. For navigator.credentials.requireUserMediation().
+  RequireUserMediation() => ();
+
+  // Get Credential. For navigator.credentials.get().
+  // The result callback will return a non-null and valid CredentialInfo
+  // if succeeded, or null with a CredentialManagerError if failed.
+  Get(bool zero_click_only, bool include_passwords, array<string> federations)
+      => (CredentialManagerError error, CredentialInfo? credential);
+};
diff --git a/components/password_manager/content/renderer/BUILD.gn b/components/password_manager/content/renderer/BUILD.gn
index 350e5b0..16629b1 100644
--- a/components/password_manager/content/renderer/BUILD.gn
+++ b/components/password_manager/content/renderer/BUILD.gn
@@ -10,11 +10,12 @@
 
   deps = [
     "//base",
-    "//components/password_manager/content/common",
+    "//components/password_manager/content/public/cpp",
     "//components/password_manager/core/common",
     "//components/strings",
+    "//content/public/common",
     "//content/public/renderer",
-    "//ipc",
+    "//mojo/common:url_type_converters",
     "//third_party/WebKit/public:blink",
     "//url",
   ]
@@ -28,9 +29,8 @@
 
   deps = [
     ":renderer",
-    "//components/password_manager/content/common",
+    "//content/public/renderer",
     "//content/test:test_support",
-    "//ipc:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//third_party/WebKit/public:blink",
diff --git a/components/password_manager/content/renderer/DEPS b/components/password_manager/content/renderer/DEPS
index 0c6d17a..488c67e 100644
--- a/components/password_manager/content/renderer/DEPS
+++ b/components/password_manager/content/renderer/DEPS
@@ -2,6 +2,7 @@
   "+content/public/common",
   "+content/public/renderer",
   "+content/test",
+  "+mojo/public",
   "+third_party/WebKit/public/platform",
   "+third_party/WebKit/public/web",
 ]
diff --git a/components/password_manager/content/renderer/credential_manager_client.cc b/components/password_manager/content/renderer/credential_manager_client.cc
index 3c548e8..c3791bc6 100644
--- a/components/password_manager/content/renderer/credential_manager_client.cc
+++ b/components/password_manager/content/renderer/credential_manager_client.cc
@@ -9,10 +9,14 @@
 #include <memory>
 #include <utility>
 
-#include "components/password_manager/content/common/credential_manager_content_utils.h"
-#include "components/password_manager/content/common/credential_manager_messages.h"
+#include "base/bind.h"
+#include "base/logging.h"
+#include "components/password_manager/content/public/cpp/type_converters.h"
 #include "components/password_manager/core/common/credential_manager_types.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
 #include "content/public/renderer/render_view.h"
+#include "mojo/common/url_type_converters.h"
 #include "third_party/WebKit/public/platform/WebCredential.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
 #include "third_party/WebKit/public/platform/WebFederatedCredential.h"
@@ -23,13 +27,128 @@
 
 namespace {
 
-template <typename T>
-void ClearCallbacksMapWithErrors(T* callbacks_map) {
-  typename T::iterator iter(callbacks_map);
-  while (!iter.IsAtEnd()) {
-    iter.GetCurrentValue()->onError(blink::WebCredentialManagerUnknownError);
-    callbacks_map->Remove(iter.GetCurrentKey());
-    iter.Advance();
+blink::WebCredentialManagerError GetWebCredentialManagerErrorFromMojo(
+    mojom::CredentialManagerError error) {
+  switch (error) {
+    case mojom::CredentialManagerError::DISABLED:
+      return blink::WebCredentialManagerError::
+          WebCredentialManagerDisabledError;
+    case mojom::CredentialManagerError::PENDINGREQUEST:
+      return blink::WebCredentialManagerError::
+          WebCredentialManagerPendingRequestError;
+    case mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE:
+      return blink::WebCredentialManagerError::
+          WebCredentialManagerPasswordStoreUnavailableError;
+    case mojom::CredentialManagerError::UNKNOWN:
+      return blink::WebCredentialManagerError::WebCredentialManagerUnknownError;
+    case mojom::CredentialManagerError::SUCCESS:
+      NOTREACHED();
+      break;
+  }
+
+  NOTREACHED();
+  return blink::WebCredentialManagerError::WebCredentialManagerUnknownError;
+}
+
+// Takes ownership of blink::WebCredentialManagerClient::NotificationCallbacks
+// pointer. When the wrapper is destroyed, if |callbacks| is still alive
+// its onError() will get called.
+class NotificationCallbacksWrapper {
+ public:
+  explicit NotificationCallbacksWrapper(
+      blink::WebCredentialManagerClient::NotificationCallbacks* callbacks);
+
+  ~NotificationCallbacksWrapper();
+
+  void NotifySuccess();
+
+ private:
+  std::unique_ptr<blink::WebCredentialManagerClient::NotificationCallbacks>
+      callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(NotificationCallbacksWrapper);
+};
+
+NotificationCallbacksWrapper::NotificationCallbacksWrapper(
+    blink::WebCredentialManagerClient::NotificationCallbacks* callbacks)
+    : callbacks_(callbacks) {}
+
+NotificationCallbacksWrapper::~NotificationCallbacksWrapper() {
+  if (callbacks_)
+    callbacks_->onError(blink::WebCredentialManagerUnknownError);
+}
+
+void NotificationCallbacksWrapper::NotifySuccess() {
+  // Call onSuccess() and reset callbacks to avoid calling onError() in
+  // destructor.
+  if (callbacks_) {
+    callbacks_->onSuccess();
+    callbacks_.reset();
+  }
+}
+
+// Takes ownership of blink::WebCredentialManagerClient::RequestCallbacks
+// pointer. When the wrapper is destroied, if |callbacks| is still alive
+// its onError() will get called.
+class RequestCallbacksWrapper {
+ public:
+  explicit RequestCallbacksWrapper(
+      blink::WebCredentialManagerClient::RequestCallbacks* callbacks);
+
+  ~RequestCallbacksWrapper();
+
+  void NotifySuccess(mojom::CredentialInfoPtr info);
+
+  void NotifyError(mojom::CredentialManagerError error);
+
+ private:
+  std::unique_ptr<blink::WebCredentialManagerClient::RequestCallbacks>
+      callbacks_;
+
+  DISALLOW_COPY_AND_ASSIGN(RequestCallbacksWrapper);
+};
+
+RequestCallbacksWrapper::RequestCallbacksWrapper(
+    blink::WebCredentialManagerClient::RequestCallbacks* callbacks)
+    : callbacks_(callbacks) {}
+
+RequestCallbacksWrapper::~RequestCallbacksWrapper() {
+  if (callbacks_)
+    callbacks_->onError(blink::WebCredentialManagerUnknownError);
+}
+
+void RequestCallbacksWrapper::NotifySuccess(mojom::CredentialInfoPtr info) {
+  // Call onSuccess() and reset callbacks to avoid calling onError() in
+  // destructor.
+  if (callbacks_) {
+    std::unique_ptr<blink::WebCredential> credential =
+        info.To<std::unique_ptr<blink::WebCredential>>();
+    callbacks_->onSuccess(std::move(credential));
+    callbacks_.reset();
+  }
+}
+
+void RequestCallbacksWrapper::NotifyError(mojom::CredentialManagerError error) {
+  if (callbacks_) {
+    callbacks_->onError(GetWebCredentialManagerErrorFromMojo(error));
+    callbacks_.reset();
+  }
+}
+
+void RespondToNotificationCallback(
+    NotificationCallbacksWrapper* callbacks_wrapper) {
+  callbacks_wrapper->NotifySuccess();
+}
+
+void RespondToRequestCallback(RequestCallbacksWrapper* callbacks_wrapper,
+                              mojom::CredentialManagerError error,
+                              mojom::CredentialInfoPtr info) {
+  if (error == mojom::CredentialManagerError::SUCCESS) {
+    DCHECK(!info.is_null());
+    callbacks_wrapper->NotifySuccess(std::move(info));
+  } else {
+    DCHECK(info.is_null());
+    callbacks_wrapper->NotifyError(error);
   }
 }
 
@@ -41,86 +160,32 @@
   render_view->GetWebView()->setCredentialManagerClient(this);
 }
 
-CredentialManagerClient::~CredentialManagerClient() {
-  ClearCallbacksMapWithErrors(&store_callbacks_);
-  ClearCallbacksMapWithErrors(&require_user_mediation_callbacks_);
-  ClearCallbacksMapWithErrors(&get_callbacks_);
-}
+CredentialManagerClient::~CredentialManagerClient() {}
 
 // -----------------------------------------------------------------------------
-// Handle messages from the browser.
-
-bool CredentialManagerClient::OnMessageReceived(const IPC::Message& message) {
-  bool handled = true;
-  IPC_BEGIN_MESSAGE_MAP(CredentialManagerClient, message)
-    IPC_MESSAGE_HANDLER(CredentialManagerMsg_AcknowledgeStore,
-                        OnAcknowledgeStore)
-    IPC_MESSAGE_HANDLER(CredentialManagerMsg_AcknowledgeRequireUserMediation,
-                        OnAcknowledgeRequireUserMediation)
-    IPC_MESSAGE_HANDLER(CredentialManagerMsg_SendCredential, OnSendCredential)
-    IPC_MESSAGE_HANDLER(CredentialManagerMsg_RejectCredentialRequest,
-                        OnRejectCredentialRequest)
-    IPC_MESSAGE_UNHANDLED(handled = false)
-  IPC_END_MESSAGE_MAP()
-  return handled;
-}
-
-void CredentialManagerClient::OnAcknowledgeStore(int request_id) {
-  RespondToNotificationCallback(request_id, &store_callbacks_);
-}
-
-void CredentialManagerClient::OnAcknowledgeRequireUserMediation(
-    int request_id) {
-  RespondToNotificationCallback(request_id, &require_user_mediation_callbacks_);
-}
-
-void CredentialManagerClient::OnSendCredential(int request_id,
-                                               const CredentialInfo& info) {
-  RequestCallbacks* callbacks = get_callbacks_.Lookup(request_id);
-  DCHECK(callbacks);
-  std::unique_ptr<blink::WebCredential> credential;
-  switch (info.type) {
-    case CredentialType::CREDENTIAL_TYPE_FEDERATED:
-      credential.reset(new blink::WebFederatedCredential(
-          info.id, info.federation, info.name, info.icon));
-      break;
-    case CredentialType::CREDENTIAL_TYPE_PASSWORD:
-      credential.reset(new blink::WebPasswordCredential(
-          info.id, info.password, info.name, info.icon));
-      break;
-    case CredentialType::CREDENTIAL_TYPE_EMPTY:
-      // Intentionally empty; we'll send nullptr to the onSuccess call below.
-      break;
-  }
-  callbacks->onSuccess(std::move(credential));
-  get_callbacks_.Remove(request_id);
-}
-
-void CredentialManagerClient::OnRejectCredentialRequest(
-    int request_id,
-    blink::WebCredentialManagerError error) {
-  RequestCallbacks* callbacks = get_callbacks_.Lookup(request_id);
-  DCHECK(callbacks);
-  callbacks->onError(error);
-  get_callbacks_.Remove(request_id);
-}
-
-// -----------------------------------------------------------------------------
-// Dispatch messages from the renderer to the browser.
+// Access mojo CredentialManagerService.
 
 void CredentialManagerClient::dispatchStore(
     const blink::WebCredential& credential,
     blink::WebCredentialManagerClient::NotificationCallbacks* callbacks) {
-  int request_id = store_callbacks_.Add(callbacks);
-  CredentialInfo info(WebCredentialToCredentialInfo(credential));
-  Send(new CredentialManagerHostMsg_Store(routing_id(), request_id, info));
+  DCHECK(callbacks);
+  ConnectToMojoCMIfNeeded();
+
+  mojom::CredentialInfoPtr info = mojom::CredentialInfo::From(credential);
+  mojo_cm_service_->Store(
+      std::move(info),
+      base::Bind(&RespondToNotificationCallback,
+                 base::Owned(new NotificationCallbacksWrapper(callbacks))));
 }
 
 void CredentialManagerClient::dispatchRequireUserMediation(
-    NotificationCallbacks* callbacks) {
-  int request_id = require_user_mediation_callbacks_.Add(callbacks);
-  Send(new CredentialManagerHostMsg_RequireUserMediation(routing_id(),
-                                                         request_id));
+    blink::WebCredentialManagerClient::NotificationCallbacks* callbacks) {
+  DCHECK(callbacks);
+  ConnectToMojoCMIfNeeded();
+
+  mojo_cm_service_->RequireUserMediation(
+      base::Bind(&RespondToNotificationCallback,
+                 base::Owned(new NotificationCallbacksWrapper(callbacks))));
 }
 
 void CredentialManagerClient::dispatchGet(
@@ -128,23 +193,27 @@
     bool include_passwords,
     const blink::WebVector<blink::WebURL>& federations,
     RequestCallbacks* callbacks) {
-  int request_id = get_callbacks_.Add(callbacks);
+  DCHECK(callbacks);
+  ConnectToMojoCMIfNeeded();
+
   std::vector<GURL> federation_vector;
   for (size_t i = 0; i < std::min(federations.size(), kMaxFederations); ++i)
     federation_vector.push_back(federations[i]);
-  Send(new CredentialManagerHostMsg_RequestCredential(
-      routing_id(), request_id, zero_click_only, include_passwords,
-      federation_vector));
+
+  mojo_cm_service_->Get(
+      zero_click_only, include_passwords,
+      mojo::Array<mojo::String>::From(federation_vector),
+      base::Bind(&RespondToRequestCallback,
+                 base::Owned(new RequestCallbacksWrapper(callbacks))));
 }
 
-void CredentialManagerClient::RespondToNotificationCallback(
-    int request_id,
-    CredentialManagerClient::NotificationCallbacksMap* map) {
-  blink::WebCredentialManagerClient::NotificationCallbacks* callbacks =
-      map->Lookup(request_id);
-  DCHECK(callbacks);
-  callbacks->onSuccess();
-  map->Remove(request_id);
+void CredentialManagerClient::ConnectToMojoCMIfNeeded() {
+  if (mojo_cm_service_)
+    return;
+
+  content::RenderFrame* main_frame = render_view()->GetMainRenderFrame();
+  main_frame->GetServiceRegistry()->ConnectToRemoteService(
+      mojo::GetProxy(&mojo_cm_service_));
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/content/renderer/credential_manager_client.h b/components/password_manager/content/renderer/credential_manager_client.h
index d87e4601..99bd96d 100644
--- a/components/password_manager/content/renderer/credential_manager_client.h
+++ b/components/password_manager/content/renderer/credential_manager_client.h
@@ -6,10 +6,9 @@
 #define COMPONENTS_PASSWORD_MANAGER_CONTENT_RENDERER_CREDENTIAL_MANAGER_CLIENT_H_
 
 #include "base/compiler_specific.h"
-#include "base/id_map.h"
 #include "base/macros.h"
+#include "components/password_manager/content/public/interfaces/credential_manager.mojom.h"
 #include "content/public/renderer/render_view_observer.h"
-#include "ipc/ipc_listener.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
 #include "third_party/WebKit/public/platform/WebVector.h"
@@ -45,19 +44,7 @@
   explicit CredentialManagerClient(content::RenderView* render_view);
   ~CredentialManagerClient() override;
 
-  // RenderViewObserver:
-  bool OnMessageReceived(const IPC::Message& message) override;
-
-  // Message handlers for messages from the browser process:
-  virtual void OnAcknowledgeStore(int request_id);
-  virtual void OnAcknowledgeRequireUserMediation(int request_id);
-  virtual void OnSendCredential(int request_id,
-                                const CredentialInfo& credential_info);
-  virtual void OnRejectCredentialRequest(
-      int request_id,
-      blink::WebCredentialManagerError error);
-
-  // blink::WebCredentialManager:
+  // blink::WebCredentialManagerClient:
   void dispatchStore(
       const blink::WebCredential& credential,
       WebCredentialManagerClient::NotificationCallbacks* callbacks) override;
@@ -68,19 +55,9 @@
                    RequestCallbacks* callbacks) override;
 
  private:
-  typedef IDMap<blink::WebCredentialManagerClient::RequestCallbacks,
-                IDMapOwnPointer> RequestCallbacksMap;
-  typedef IDMap<blink::WebCredentialManagerClient::NotificationCallbacks,
-                IDMapOwnPointer> NotificationCallbacksMap;
+  void ConnectToMojoCMIfNeeded();
 
-  void RespondToNotificationCallback(int request_id,
-                                     NotificationCallbacksMap* map);
-
-  // Track the various blink::WebCredentialManagerClient::*Callbacks objects
-  // generated from Blink. This class takes ownership of these objects.
-  NotificationCallbacksMap store_callbacks_;
-  NotificationCallbacksMap require_user_mediation_callbacks_;
-  RequestCallbacksMap get_callbacks_;
+  mojom::CredentialManagerPtr mojo_cm_service_;
 
   DISALLOW_COPY_AND_ASSIGN(CredentialManagerClient);
 };
diff --git a/components/password_manager/content/renderer/credential_manager_client_browsertest.cc b/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
index addbcf2a..67dca8f 100644
--- a/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
+++ b/components/password_manager/content/renderer/credential_manager_client_browsertest.cc
@@ -9,19 +9,70 @@
 #include <memory>
 #include <tuple>
 
-#include "components/password_manager/content/common/credential_manager_messages.h"
+#include "content/public/common/service_registry.h"
+#include "content/public/renderer/render_frame.h"
+#include "content/public/renderer/render_view.h"
 #include "content/public/test/render_view_test.h"
-#include "ipc/ipc_test_sink.h"
+#include "mojo/public/cpp/bindings/binding_set.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/WebKit/public/platform/WebCredential.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerClient.h"
 #include "third_party/WebKit/public/platform/WebCredentialManagerError.h"
 #include "third_party/WebKit/public/platform/WebPasswordCredential.h"
 
+using content::ServiceRegistry;
+
 namespace password_manager {
 
 namespace {
 
+const char kTestCredentialPassword[] = "https://password.com/";
+const char kTestCredentialEmpty[] = "https://empty.com/";
+const char kTestCredentialReject[] = "https://reject.com/";
+
+class FakeCredentialManager : public mojom::CredentialManager {
+ public:
+  FakeCredentialManager() {}
+  ~FakeCredentialManager() override {}
+
+  void BindRequest(mojom::CredentialManagerRequest request) {
+    bindings_.AddBinding(this, std::move(request));
+  }
+
+ private:
+  // mojom::CredentialManager methods:
+  void Store(mojom::CredentialInfoPtr credential,
+             const StoreCallback& callback) override {
+    callback.Run();
+  }
+
+  void RequireUserMediation(
+      const RequireUserMediationCallback& callback) override {
+    callback.Run();
+  }
+
+  void Get(bool zero_click_only,
+           bool include_passwords,
+           mojo::Array<mojo::String> federations,
+           const GetCallback& callback) override {
+    mojo::String& url = federations[0];
+
+    if (url == kTestCredentialPassword) {
+      mojom::CredentialInfoPtr info = mojom::CredentialInfo::New();
+      info->type = mojom::CredentialType::PASSWORD;
+      callback.Run(mojom::CredentialManagerError::SUCCESS, std::move(info));
+    } else if (url == kTestCredentialEmpty) {
+      callback.Run(mojom::CredentialManagerError::SUCCESS,
+                   mojom::CredentialInfo::New());
+    } else if (url == kTestCredentialReject) {
+      callback.Run(mojom::CredentialManagerError::PASSWORDSTOREUNAVAILABLE,
+                   nullptr);
+    }
+  }
+
+  mojo::BindingSet<mojom::CredentialManager> bindings_;
+};
+
 class CredentialManagerClientTest : public content::RenderViewTest {
  public:
   CredentialManagerClientTest()
@@ -30,8 +81,14 @@
 
   void SetUp() override {
     content::RenderViewTest::SetUp();
-    credential_.reset(new blink::WebPasswordCredential("", "", "", GURL()));
     client_.reset(new CredentialManagerClient(view_));
+
+    ServiceRegistry* registry =
+        view_->GetMainRenderFrame()->GetServiceRegistry();
+    registry->AddServiceOverrideForTesting(
+        mojom::CredentialManager::Name_,
+        base::Bind(&CredentialManagerClientTest::BindCredentialManager,
+                   base::Unretained(this)));
   }
 
   void TearDown() override {
@@ -40,60 +97,24 @@
     content::RenderViewTest::TearDown();
   }
 
-  IPC::TestSink& sink() { return render_thread_->sink(); }
-
-  blink::WebCredential* credential() { return credential_.get(); }
-
-  // The browser's response to any of the messages the client sends must contain
-  // a request ID so that the client knows which request is being serviced. This
-  // method grabs the ID from an outgoing |message_id| message, and sets the
-  // |request_id| param to its value. If no request ID can be found, the method
-  // returns false, and the |request_id| is set to -1.
-  //
-  // Clears any pending messages upon return.
-  bool ExtractRequestId(uint32_t message_id, int& request_id) {
-    request_id = -1;
-    const IPC::Message* message = sink().GetFirstMessageMatching(message_id);
-    if (!message)
-      return false;
-
-    switch (message_id) {
-      case CredentialManagerHostMsg_Store::ID: {
-        std::tuple<int, CredentialInfo> param;
-        CredentialManagerHostMsg_Store::Read(message, &param);
-        request_id = std::get<0>(param);
-        break;
-      }
-
-      case CredentialManagerHostMsg_RequireUserMediation::ID: {
-        std::tuple<int> param;
-        CredentialManagerHostMsg_RequireUserMediation::Read(message, &param);
-        request_id = std::get<0>(param);
-        break;
-      }
-
-      case CredentialManagerHostMsg_RequestCredential::ID: {
-        std::tuple<int, bool, bool, std::vector<GURL>> param;
-        CredentialManagerHostMsg_RequestCredential::Read(message, &param);
-        request_id = std::get<0>(param);
-        break;
-      }
-
-      default:
-        break;
-    }
-    sink().ClearMessages();
-    return request_id != -1;
-  }
-
   bool callback_errored() const { return callback_errored_; }
   void set_callback_errored(bool state) { callback_errored_ = state; }
   bool callback_succeeded() const { return callback_succeeded_; }
   void set_callback_succeeded(bool state) { callback_succeeded_ = state; }
 
+  void BindCredentialManager(mojo::ScopedMessagePipeHandle handle) {
+    fake_cm_.BindRequest(
+        mojo::MakeRequest<mojom::CredentialManager>(std::move(handle)));
+  }
+
+  std::unique_ptr<blink::WebPasswordCredential> credential_;
+  blink::WebCredentialManagerError error_;
+
  protected:
   std::unique_ptr<CredentialManagerClient> client_;
 
+  FakeCredentialManager fake_cm_;
+
   // True if a message's callback's 'onSuccess'/'onError' methods were called,
   // false otherwise. We put these on the test object rather than on the
   // Test*Callbacks objects because ownership of those objects passes into the
@@ -101,8 +122,6 @@
   // pending Blink-side Promise.
   bool callback_errored_;
   bool callback_succeeded_;
-
-  std::unique_ptr<blink::WebPasswordCredential> credential_;
 };
 
 class TestNotificationCallbacks
@@ -131,90 +150,99 @@
 
   ~TestRequestCallbacks() override {}
 
-  void onSuccess(std::unique_ptr<blink::WebCredential>) override {
+  void onSuccess(std::unique_ptr<blink::WebCredential> credential) override {
     test_->set_callback_succeeded(true);
+
+    blink::WebCredential* ptr = credential.release();
+    test_->credential_.reset(static_cast<blink::WebPasswordCredential*>(ptr));
   }
 
   void onError(blink::WebCredentialManagerError reason) override {
     test_->set_callback_errored(true);
+    test_->credential_.reset();
+    test_->error_ = reason;
   }
 
  private:
   CredentialManagerClientTest* test_;
 };
 
+void RunAllPendingTasks() {
+  base::RunLoop run_loop;
+  base::MessageLoop::current()->PostTask(
+      FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
+  run_loop.Run();
+}
+
 }  // namespace
 
 TEST_F(CredentialManagerClientTest, SendStore) {
-  int request_id;
-  EXPECT_FALSE(
-      ExtractRequestId(CredentialManagerHostMsg_Store::ID, request_id));
-
+  credential_.reset(new blink::WebPasswordCredential("", "", "", GURL()));
   std::unique_ptr<TestNotificationCallbacks> callbacks(
       new TestNotificationCallbacks(this));
-  client_->dispatchStore(*credential(), callbacks.release());
+  client_->dispatchStore(*credential_, callbacks.release());
 
-  EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_Store::ID, request_id));
+  RunAllPendingTasks();
 
-  client_->OnAcknowledgeStore(request_id);
   EXPECT_TRUE(callback_succeeded());
   EXPECT_FALSE(callback_errored());
 }
 
 TEST_F(CredentialManagerClientTest, SendRequestUserMediation) {
-  int request_id;
-  EXPECT_FALSE(ExtractRequestId(
-      CredentialManagerHostMsg_RequireUserMediation::ID, request_id));
-
   std::unique_ptr<TestNotificationCallbacks> callbacks(
       new TestNotificationCallbacks(this));
   client_->dispatchRequireUserMediation(callbacks.release());
 
-  EXPECT_TRUE(ExtractRequestId(
-      CredentialManagerHostMsg_RequireUserMediation::ID, request_id));
+  RunAllPendingTasks();
 
-  client_->OnAcknowledgeRequireUserMediation(request_id);
   EXPECT_TRUE(callback_succeeded());
   EXPECT_FALSE(callback_errored());
 }
 
 TEST_F(CredentialManagerClientTest, SendRequestCredential) {
-  int request_id;
-  EXPECT_FALSE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID,
-                                request_id));
-
   std::unique_ptr<TestRequestCallbacks> callbacks(
       new TestRequestCallbacks(this));
   std::vector<GURL> federations;
+  federations.push_back(GURL(kTestCredentialPassword));
   client_->dispatchGet(false, true, federations, callbacks.release());
 
-  EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID,
-                               request_id));
+  RunAllPendingTasks();
 
-  CredentialInfo info;
-  info.type = CredentialType::CREDENTIAL_TYPE_PASSWORD;
-  client_->OnSendCredential(request_id, info);
   EXPECT_TRUE(callback_succeeded());
   EXPECT_FALSE(callback_errored());
+  EXPECT_TRUE(credential_);
+  EXPECT_EQ("password", credential_->type());
 }
 
 TEST_F(CredentialManagerClientTest, SendRequestCredentialEmpty) {
-  int request_id;
-  EXPECT_FALSE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID,
-                                request_id));
-
   std::unique_ptr<TestRequestCallbacks> callbacks(
       new TestRequestCallbacks(this));
   std::vector<GURL> federations;
+  federations.push_back(GURL(kTestCredentialEmpty));
   client_->dispatchGet(false, true, federations, callbacks.release());
 
-  EXPECT_TRUE(ExtractRequestId(CredentialManagerHostMsg_RequestCredential::ID,
-                               request_id));
+  RunAllPendingTasks();
 
-  CredentialInfo info;  // Send an empty credential in response.
-  client_->OnSendCredential(request_id, info);
   EXPECT_TRUE(callback_succeeded());
   EXPECT_FALSE(callback_errored());
+  EXPECT_FALSE(credential_);
+}
+
+TEST_F(CredentialManagerClientTest, SendRequestCredentialReject) {
+  std::unique_ptr<TestRequestCallbacks> callbacks(
+      new TestRequestCallbacks(this));
+  std::vector<GURL> federations;
+  federations.push_back(GURL(kTestCredentialReject));
+  client_->dispatchGet(false, true, federations, callbacks.release());
+
+  RunAllPendingTasks();
+
+  EXPECT_FALSE(callback_succeeded());
+  EXPECT_TRUE(callback_errored());
+  EXPECT_FALSE(credential_);
+  EXPECT_EQ(blink::WebCredentialManagerError::
+                WebCredentialManagerPasswordStoreUnavailableError,
+            error_);
 }
 
 }  // namespace password_manager
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.cc b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
index 1e1b6cd..a852003 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.cc
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.cc
@@ -19,14 +19,14 @@
 
 CredentialManagerPendingRequestTask::CredentialManagerPendingRequestTask(
     CredentialManagerPendingRequestTaskDelegate* delegate,
-    int request_id,
+    const SendCredentialCallback& callback,
     bool request_zero_click_only,
     const GURL& request_origin,
     bool include_passwords,
     const std::vector<GURL>& request_federations,
     const std::vector<std::string>& affiliated_realms)
     : delegate_(delegate),
-      id_(request_id),
+      send_callback_(callback),
       zero_click_only_(request_zero_click_only),
       origin_(request_origin),
       include_passwords_(include_passwords),
@@ -42,7 +42,7 @@
 void CredentialManagerPendingRequestTask::OnGetPasswordStoreResults(
     ScopedVector<autofill::PasswordForm> results) {
   if (delegate_->GetOrigin() != origin_) {
-    delegate_->SendCredential(id_, CredentialInfo());
+    delegate_->SendCredential(send_callback_, CredentialInfo());
     return;
   }
 
@@ -88,7 +88,7 @@
   }
 
   if ((local_results.empty() && federated_results.empty())) {
-    delegate_->SendCredential(id_, CredentialInfo());
+    delegate_->SendCredential(send_callback_, CredentialInfo());
     return;
   }
 
@@ -109,7 +109,7 @@
                             : CredentialType::CREDENTIAL_TYPE_FEDERATED);
     delegate_->client()->NotifyUserAutoSignin(std::move(local_results),
                                               origin_);
-    delegate_->SendCredential(id_, info);
+    delegate_->SendCredential(send_callback_, info);
     return;
   }
 
@@ -123,7 +123,7 @@
           std::move(local_results), std::move(federated_results), origin_,
           base::Bind(
               &CredentialManagerPendingRequestTaskDelegate::SendPasswordForm,
-              base::Unretained(delegate_), id_))) {
+              base::Unretained(delegate_), send_callback_))) {
     if (can_use_autosignin) {
       // The user had credentials, but either chose not to share them with the
       // site, or was prevented from doing so by lack of zero-click (or the
@@ -134,7 +134,7 @@
           std::move(potential_autosignin_form));
     }
 
-    delegate_->SendCredential(id_, CredentialInfo());
+    delegate_->SendCredential(send_callback_, CredentialInfo());
   }
 }
 
diff --git a/components/password_manager/core/browser/credential_manager_pending_request_task.h b/components/password_manager/core/browser/credential_manager_pending_request_task.h
index 61211b2..1cafaf1b 100644
--- a/components/password_manager/core/browser/credential_manager_pending_request_task.h
+++ b/components/password_manager/core/browser/credential_manager_pending_request_task.h
@@ -24,6 +24,9 @@
 struct CredentialInfo;
 class PasswordManagerClient;
 
+typedef base::Callback<void(const CredentialInfo& credential)>
+    SendCredentialCallback;
+
 // Sends credentials retrieved from the PasswordStore to CredentialManager API
 // clients and retrieves embedder-dependent information.
 class CredentialManagerPendingRequestTaskDelegate {
@@ -41,11 +44,13 @@
   virtual PasswordManagerClient* client() const = 0;
 
   // Sends a credential to JavaScript.
-  virtual void SendCredential(int id, const CredentialInfo& credential) = 0;
+  virtual void SendCredential(const SendCredentialCallback& send_callback,
+                              const CredentialInfo& credential) = 0;
 
   // Updates |skip_zero_click| for |form| in the PasswordStore if required.
   // Sends a credential to JavaScript.
-  virtual void SendPasswordForm(int id, const autofill::PasswordForm* form) = 0;
+  virtual void SendPasswordForm(const SendCredentialCallback& send_callback,
+                                const autofill::PasswordForm* form) = 0;
 };
 
 // Retrieves credentials from the PasswordStore.
@@ -53,7 +58,7 @@
  public:
   CredentialManagerPendingRequestTask(
       CredentialManagerPendingRequestTaskDelegate* delegate,
-      int request_id,
+      const SendCredentialCallback& callback,
       bool request_zero_click_only,
       const GURL& request_origin,
       bool include_passwords,
@@ -61,7 +66,7 @@
       const std::vector<std::string>& affiliated_realms);
   ~CredentialManagerPendingRequestTask() override;
 
-  int id() const { return id_; }
+  SendCredentialCallback send_callback() const { return send_callback_; }
   const GURL& origin() const { return origin_; }
 
   // PasswordStoreConsumer implementation.
@@ -70,7 +75,7 @@
 
  private:
   CredentialManagerPendingRequestTaskDelegate* delegate_;  // Weak;
-  const int id_;
+  SendCredentialCallback send_callback_;
   const bool zero_click_only_;
   const GURL origin_;
   const bool include_passwords_;
diff --git a/components/password_manager/core/browser/password_manager.h b/components/password_manager/core/browser/password_manager.h
index 1adc983..79ba10c 100644
--- a/components/password_manager/core/browser/password_manager.h
+++ b/components/password_manager/core/browser/password_manager.h
@@ -37,9 +37,6 @@
 class PasswordManagerDriver;
 class PasswordFormManager;
 
-// TODO(melandory): Separate the PasswordFormManager API interface and the
-// implementation in two classes http://crbug.com/473184.
-
 // Per-tab password manager. Handles creation and management of UI elements,
 // receiving password form data from the renderer and managing the password
 // database through the PasswordStore. The PasswordManager is a LoginModel
diff --git a/components/password_manager/core/common/credential_manager_types.cc b/components/password_manager/core/common/credential_manager_types.cc
index 8f364867e..6d431e1a 100644
--- a/components/password_manager/core/common/credential_manager_types.cc
+++ b/components/password_manager/core/common/credential_manager_types.cc
@@ -9,8 +9,16 @@
 
 namespace password_manager {
 
-std::ostream& operator<<(std::ostream& out, CredentialType type) {
-  return out << static_cast<int>(type);
+std::ostream& operator<<(std::ostream& os, CredentialType value) {
+  switch (value) {
+    case CredentialType::CREDENTIAL_TYPE_EMPTY:
+      return os << "CredentialType::CREDENTIAL_TYPE_EMPTY";
+    case CredentialType::CREDENTIAL_TYPE_PASSWORD:
+      return os << "CredentialType::CREDENTIAL_TYPE_PASSWORD";
+    case CredentialType::CREDENTIAL_TYPE_FEDERATED:
+      return os << "CredentialType::CREDENTIAL_TYPE_FEDERATED";
+  }
+  return os << "Unknown CredentialType value: " << static_cast<int32_t>(value);
 }
 
 CredentialInfo::CredentialInfo() : type(CredentialType::CREDENTIAL_TYPE_EMPTY) {
diff --git a/components/password_manager/core/common/credential_manager_types.h b/components/password_manager/core/common/credential_manager_types.h
index dbe84fd..2b98e3f 100644
--- a/components/password_manager/core/common/credential_manager_types.h
+++ b/components/password_manager/core/common/credential_manager_types.h
@@ -8,6 +8,7 @@
 #include <stddef.h>
 
 #include <memory>
+#include <ostream>
 #include <string>
 
 #include "base/compiler_specific.h"
@@ -32,7 +33,7 @@
   CREDENTIAL_TYPE_LAST = CREDENTIAL_TYPE_FEDERATED
 };
 
-std::ostream& operator<<(std::ostream& out, CredentialType type);
+std::ostream& operator<<(std::ostream& os, CredentialType value);
 
 struct CredentialInfo {
   CredentialInfo();
diff --git a/components/profile_service/BUILD.gn b/components/profile_service/BUILD.gn
index 67954ad..f6e6a21 100644
--- a/components/profile_service/BUILD.gn
+++ b/components/profile_service/BUILD.gn
@@ -25,9 +25,9 @@
     "//mojo/common:common_base",
     "//mojo/message_pump",
     "//mojo/platform_handle",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
     "//services/shell/public/interfaces",
+    "//services/tracing/public/cpp",
     "//url",
   ]
 }
diff --git a/components/profile_service/DEPS b/components/profile_service/DEPS
index e854d1e0..41f8d40d 100644
--- a/components/profile_service/DEPS
+++ b/components/profile_service/DEPS
@@ -5,7 +5,7 @@
   "+mojo/message_pump",
   "+mojo/platform_handle",
   "+mojo/public",
-  "+mojo/services/tracing/public/cpp",
-  "+services/shell",
   "+mojo/util",
+  "+services/shell",
+  "+services/tracing/public/cpp",
 ]
diff --git a/components/profile_service/profile_app.h b/components/profile_service/profile_app.h
index 78f1d07b..0fff6c42 100644
--- a/components/profile_service/profile_app.h
+++ b/components/profile_service/profile_app.h
@@ -10,9 +10,9 @@
 #include "components/leveldb/public/interfaces/leveldb.mojom.h"
 #include "components/profile_service/public/interfaces/profile.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace profile {
 
diff --git a/components/profile_service/profile_service.gyp b/components/profile_service/profile_service.gyp
index e562b71..da787ac 100644
--- a/components/profile_service/profile_service.gyp
+++ b/components/profile_service/profile_service.gyp
@@ -30,9 +30,8 @@
         '../../base/base.gyp:base',
         '../../components/filesystem/filesystem.gyp:filesystem_lib',
         '../../components/leveldb/leveldb.gyp:leveldb_lib',
-        '../../mojo/mojo_base.gyp:mojo_application_base',
-        '../../mojo/mojo_base.gyp:mojo_application_bindings',
-        '../../mojo/mojo_base.gyp:tracing_service',
+        '../../services/shell/shell.gyp:shell_public',
+        '../../services/tracing/tracing.gyp:tracing_lib',
         '../../mojo/mojo_edk.gyp:mojo_system_impl',
         '../../mojo/mojo_public.gyp:mojo_cpp_bindings',
         '../../mojo/mojo_platform_handle.gyp:platform_handle',
diff --git a/components/resource_provider/BUILD.gn b/components/resource_provider/BUILD.gn
index 040a150..26054e3d 100644
--- a/components/resource_provider/BUILD.gn
+++ b/components/resource_provider/BUILD.gn
@@ -104,8 +104,8 @@
     "//components/resource_provider/public/interfaces",
     "//mojo/common:common_base",
     "//mojo/platform_handle",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//url",
   ]
 }
diff --git a/components/resource_provider/DEPS b/components/resource_provider/DEPS
index 2d1f0ab..4dc9b3b 100644
--- a/components/resource_provider/DEPS
+++ b/components/resource_provider/DEPS
@@ -4,5 +4,5 @@
   "+mojo/converters",
   "+mojo/platform_handle",
   "+mojo/public",
-  "+mojo/services/tracing/public/cpp",
+  "+services/tracing/public/cpp",
 ]
diff --git a/components/resource_provider/resource_provider_app.h b/components/resource_provider/resource_provider_app.h
index 103df3ce..5861abe 100644
--- a/components/resource_provider/resource_provider_app.h
+++ b/components/resource_provider/resource_provider_app.h
@@ -11,9 +11,9 @@
 #include "components/resource_provider/public/interfaces/resource_provider.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace resource_provider {
 
diff --git a/components/url_formatter/url_fixer.cc b/components/url_formatter/url_fixer.cc
index 04092636..e227d78 100644
--- a/components/url_formatter/url_fixer.cc
+++ b/components/url_formatter/url_fixer.cc
@@ -411,11 +411,11 @@
   int trimmed_length = static_cast<int>(trimmed.length());
   if (url::DoesBeginWindowsDriveSpec(trimmed.data(), 0, trimmed_length) ||
       url::DoesBeginUNCPath(trimmed.data(), 0, trimmed_length, true))
-    return "file";
+    return url::kFileScheme;
 #elif defined(OS_POSIX)
   if (base::FilePath::IsSeparator(trimmed.data()[0]) ||
       trimmed.data()[0] == '~')
-    return "file";
+    return url::kFileScheme;
 #endif
 
   // Otherwise, we need to look at things carefully.
diff --git a/content/BUILD.gn b/content/BUILD.gn
index 56941b8f..2193f545 100644
--- a/content/BUILD.gn
+++ b/content/BUILD.gn
@@ -117,7 +117,7 @@
   deps = [
     "//content/public/app:browser_manifest",
     "//content/public/app:renderer_manifest",
-    "//mojo/services/catalog:manifest",
+    "//services/catalog:manifest",
   ]
 }
 
diff --git a/content/DEPS b/content/DEPS
index f5efa16c..1d6f952 100644
--- a/content/DEPS
+++ b/content/DEPS
@@ -81,7 +81,6 @@
   "+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/android/in_process/synchronous_input_event_filter.cc b/content/browser/android/in_process/synchronous_input_event_filter.cc
index ff378b2..b4d9f7f 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 using blink::WebInputEvent;
 
diff --git a/content/browser/compositor/image_transport_factory.h b/content/browser/compositor/image_transport_factory.h
index c334c80..8a398bd 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 1ceacaae..4413c4c3 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/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index fcf2ff3..2e30fec 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 98003ce7..59b6d00 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 using std::string;
 
diff --git a/content/browser/mojo/mojo_shell_context.cc b/content/browser/mojo/mojo_shell_context.cc
index 186b960..0d134152 100644
--- a/content/browser/mojo/mojo_shell_context.cc
+++ b/content/browser/mojo/mojo_shell_context.cc
@@ -32,9 +32,9 @@
 #include "content/public/common/service_registry.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/string.h"
-#include "mojo/services/catalog/factory.h"
-#include "mojo/services/catalog/manifest_provider.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/factory.h"
+#include "services/catalog/manifest_provider.h"
+#include "services/catalog/store.h"
 #include "services/shell/connect_params.h"
 #include "services/shell/loader.h"
 #include "services/shell/native_runner.h"
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 1c3bd74..7711e2d 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/latency_info/latency_info.h"
+#include "ui/events/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 2afffe8..633e4e8 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/latency_info/latency_info.h"
+#include "ui/events/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 74abdc6..e1fd3b0 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/latency_info/latency_info.h"
+#include "ui/events/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 cb144b1..6353f34 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/latency_info/latency_info.h"
+#include "ui/events/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 1242d826..46dc23ae 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/latency_info/latency_info.h"
+#include "ui/events/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 6fff6819..3a317822b 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/latency_info/latency_info.h"
+#include "ui/events/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 17516af..2c4ab95 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/latency_info/latency_info.h"
+#include "ui/events/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 d374b2c..7ff1dd0 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 using blink::WebInputEvent;
 
diff --git a/content/browser/renderer_host/render_widget_host_impl.h b/content/browser/renderer_host/render_widget_host_impl.h
index 7dfd14d..43047c2 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/renderer_host/sandbox_ipc_linux.cc b/content/browser/renderer_host/sandbox_ipc_linux.cc
index 94a34b5..b6ba92d 100644
--- a/content/browser/renderer_host/sandbox_ipc_linux.cc
+++ b/content/browser/renderer_host/sandbox_ipc_linux.cc
@@ -173,19 +173,20 @@
     int fd,
     base::PickleIterator iter,
     const std::vector<base::ScopedFD>& fds) {
-  uint32_t requested_style;
+  SkFontStyle requested_style;
   std::string family;
-  if (!iter.ReadString(&family) || !iter.ReadUInt32(&requested_style))
+  if (!iter.ReadString(&family) ||
+      !skia::ReadSkFontStyle(&iter, &requested_style))
     return;
 
   SkFontConfigInterface::FontIdentity result_identity;
   SkString result_family;
-  SkTypeface::Style result_style;
+  SkFontStyle result_style;
   SkFontConfigInterface* fc =
       SkFontConfigInterface::GetSingletonDirectInterface();
   const bool r =
       fc->matchFamilyName(family.c_str(),
-                          static_cast<SkTypeface::Style>(requested_style),
+                          requested_style,
                           &result_identity,
                           &result_family,
                           &result_style);
@@ -202,7 +203,7 @@
     reply.WriteBool(true);
     skia::WriteSkString(&reply, result_family);
     skia::WriteSkFontIdentity(&reply, result_identity);
-    reply.WriteUInt32(result_style);
+    skia::WriteSkFontStyle(&reply, result_style);
   }
   SendRendererReply(fds, reply, -1);
 }
diff --git a/content/child/font_warmup_win_unittest.cc b/content/child/font_warmup_win_unittest.cc
index fc86017..ef89549 100644
--- a/content/child/font_warmup_win_unittest.cc
+++ b/content/child/font_warmup_win_unittest.cc
@@ -201,7 +201,7 @@
   }
 
   SkTypeface* onLegacyCreateTypeface(const char familyName[],
-                                     unsigned styleBits) const override {
+                                     SkFontStyle style) const override {
     ADD_FAILURE();
     return nullptr;
   }
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index fc115a82..ee96ebc 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",
diff --git a/content/common/accelerated_surface_buffers_swapped_params_mac.h b/content/common/accelerated_surface_buffers_swapped_params_mac.h
index a25a41a..71fb4ff 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/font_config_ipc_linux.cc b/content/common/font_config_ipc_linux.cc
index 08fed23..fff2fb9 100644
--- a/content/common/font_config_ipc_linux.cc
+++ b/content/common/font_config_ipc_linux.cc
@@ -64,10 +64,10 @@
 }
 
 bool FontConfigIPC::matchFamilyName(const char familyName[],
-                                    SkTypeface::Style requestedStyle,
+                                    SkFontStyle requestedStyle,
                                     FontIdentity* outFontIdentity,
                                     SkString* outFamilyName,
-                                    SkTypeface::Style* outStyle) {
+                                    SkFontStyle* outStyle) {
   TRACE_EVENT0("sandbox_ipc", "FontConfigIPC::matchFamilyName");
   size_t familyNameLen = familyName ? strlen(familyName) : 0;
   if (familyNameLen > kMaxFontFamilyLength)
@@ -76,7 +76,7 @@
   base::Pickle request;
   request.WriteInt(METHOD_MATCH);
   request.WriteData(familyName, familyNameLen);
-  request.WriteUInt32(requestedStyle);
+  skia::WriteSkFontStyle(&request, requestedStyle);
 
   uint8_t reply_buf[2048];
   const ssize_t r = base::UnixDomainSocket::SendRecvMsg(
@@ -94,10 +94,10 @@
 
   SkString     reply_family;
   FontIdentity reply_identity;
-  uint32_t     reply_style;
+  SkFontStyle  reply_style;
   if (!skia::ReadSkString(&iter, &reply_family) ||
       !skia::ReadSkFontIdentity(&iter, &reply_identity) ||
-      !iter.ReadUInt32(&reply_style)) {
+      !skia::ReadSkFontStyle(&iter, &reply_style)) {
     return false;
   }
 
@@ -106,7 +106,7 @@
   if (outFamilyName)
     *outFamilyName = reply_family;
   if (outStyle)
-    *outStyle = static_cast<SkTypeface::Style>(reply_style);
+    *outStyle = reply_style;
 
   return true;
 }
diff --git a/content/common/font_config_ipc_linux.h b/content/common/font_config_ipc_linux.h
index 5e969cd..59a4b0f4 100644
--- a/content/common/font_config_ipc_linux.h
+++ b/content/common/font_config_ipc_linux.h
@@ -34,10 +34,10 @@
   ~FontConfigIPC() override;
 
   bool matchFamilyName(const char familyName[],
-                       SkTypeface::Style requested,
+                       SkFontStyle requested,
                        FontIdentity* outFontIdentifier,
                        SkString* outFamilyName,
-                       SkTypeface::Style* outStyle) override;
+                       SkFontStyle* outStyle) override;
 
   // Returns a new SkTypeface instance or a ref'ed one from the cache. The
   // caller should adopt the pointer.
diff --git a/content/common/gpu/media/v4l2_image_processor.cc b/content/common/gpu/media/v4l2_image_processor.cc
index b7417b5..96838c4 100644
--- a/content/common/gpu/media/v4l2_image_processor.cc
+++ b/content/common/gpu/media/v4l2_image_processor.cc
@@ -18,12 +18,6 @@
 #include "content/common/gpu/media/v4l2_image_processor.h"
 #include "media/base/bind_to_current_loop.h"
 
-#define NOTIFY_ERROR()                      \
-  do {                                      \
-    LOG(ERROR) << "calling NotifyError()";  \
-    NotifyError();                          \
-  } while (0)
-
 #define IOCTL_OR_ERROR_RETURN_VALUE(type, arg, value, type_str)        \
   do {                                                                 \
     if (device_->Ioctl(type, arg) != 0) {                              \
@@ -78,7 +72,9 @@
       output_streamon_(false),
       output_buffer_queued_count_(0),
       num_buffers_(0),
-      device_weak_factory_(this) {}
+      weak_this_factory_(this) {
+  weak_this_ = weak_this_factory_.GetWeakPtr();
+}
 
 V4L2ImageProcessor::~V4L2ImageProcessor() {
   DCHECK(child_task_runner_->BelongsToCurrentThread());
@@ -90,10 +86,17 @@
 }
 
 void V4L2ImageProcessor::NotifyError() {
-  if (!child_task_runner_->BelongsToCurrentThread())
-    child_task_runner_->PostTask(FROM_HERE, error_cb_);
-  else
-    error_cb_.Run();
+  LOG(ERROR) << __func__;
+  DCHECK(!child_task_runner_->BelongsToCurrentThread());
+  child_task_runner_->PostTask(
+      FROM_HERE, base::Bind(&V4L2ImageProcessor::NotifyErrorOnChildThread,
+                            weak_this_, error_cb_));
+}
+
+void V4L2ImageProcessor::NotifyErrorOnChildThread(
+    const base::Closure& error_cb) {
+  DCHECK(child_task_runner_->BelongsToCurrentThread());
+  error_cb_.Run();
 }
 
 bool V4L2ImageProcessor::Initialize(const base::Closure& error_cb,
@@ -154,7 +157,7 @@
     return false;
   }
 
-  // StartDevicePoll will NOTIFY_ERROR on failure, so IgnoreResult is fine here.
+  // StartDevicePoll will NotifyError on failure, so IgnoreResult is fine here.
   device_thread_.message_loop()->PostTask(
       FROM_HERE,
       base::Bind(base::IgnoreResult(&V4L2ImageProcessor::StartDevicePoll),
@@ -212,6 +215,8 @@
   DVLOG(3) << __func__;
   DCHECK(child_task_runner_->BelongsToCurrentThread());
 
+  weak_this_factory_.InvalidateWeakPtrs();
+
   // If the device thread is running, destroy using posted task.
   if (device_thread_.IsRunning()) {
     device_thread_.message_loop()->PostTask(
@@ -222,7 +227,6 @@
   } else {
     // Otherwise DestroyTask() is not needed.
     DCHECK(!device_poll_thread_.IsRunning());
-    DCHECK(!device_weak_factory_.HasWeakPtrs());
   }
 
   delete this;
@@ -231,8 +235,6 @@
 void V4L2ImageProcessor::DestroyTask() {
   DCHECK_EQ(device_thread_.message_loop(), base::MessageLoop::current());
 
-  device_weak_factory_.InvalidateWeakPtrs();
-
   // Stop streaming and the device_poll_thread_.
   StopDevicePoll();
 }
@@ -401,7 +403,7 @@
 
   bool event_pending;
   if (!device_->Poll(poll_device, &event_pending)) {
-    NOTIFY_ERROR();
+    NotifyError();
     return;
   }
 
@@ -510,7 +512,7 @@
         break;
       }
       PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
-      NOTIFY_ERROR();
+      NotifyError();
       return;
     }
     InputRecord& input_record = input_buffer_map_[dqbuf.index];
@@ -537,7 +539,7 @@
         break;
       }
       PLOG(ERROR) << "ioctl() failed: VIDIOC_DQBUF";
-      NOTIFY_ERROR();
+      NotifyError();
       return;
     }
     OutputRecord& output_record = output_buffer_map_[dqbuf.index];
@@ -552,8 +554,9 @@
 
     DVLOG(3) << "Processing finished, returning frame, index=" << dqbuf.index;
 
-    child_task_runner_->PostTask(FROM_HERE,
-                                 base::Bind(job_record->ready_cb, dqbuf.index));
+    child_task_runner_->PostTask(
+        FROM_HERE, base::Bind(&V4L2ImageProcessor::FrameReady, weak_this_,
+                              job_record->ready_cb, dqbuf.index));
   }
 }
 
@@ -625,7 +628,7 @@
   // Start up the device poll thread and schedule its first DevicePollTask().
   if (!device_poll_thread_.Start()) {
     LOG(ERROR) << "StartDevicePoll(): Device thread failed to start";
-    NOTIFY_ERROR();
+    NotifyError();
     return false;
   }
   // Enqueue a poll task with no devices to poll on - will wait only for the
@@ -687,4 +690,10 @@
   return true;
 }
 
+void V4L2ImageProcessor::FrameReady(const FrameReadyCB& cb,
+                                    int output_buffer_index) {
+  DCHECK(child_task_runner_->BelongsToCurrentThread());
+  cb.Run(output_buffer_index);
+}
+
 }  // namespace content
diff --git a/content/common/gpu/media/v4l2_image_processor.h b/content/common/gpu/media/v4l2_image_processor.h
index 80137c3..72caf3d 100644
--- a/content/common/gpu/media/v4l2_image_processor.h
+++ b/content/common/gpu/media/v4l2_image_processor.h
@@ -67,7 +67,9 @@
                int output_buffer_index,
                const FrameReadyCB& cb);
 
-  // Stop all processing and clean up.
+  // Stop all processing and clean up. After this method returns no more
+  // callbacks will be invoked.  Deletes |this| unconditionally, so make sure
+  // to drop all pointers to it!
   void Destroy();
 
  private:
@@ -109,6 +111,7 @@
   void DestroyOutputBuffers();
 
   void NotifyError();
+  void NotifyErrorOnChildThread(const base::Closure& error_cb);
   void DestroyTask();
 
   void ProcessTask(std::unique_ptr<JobRecord> job_record);
@@ -121,6 +124,9 @@
   // Ran on device_poll_thread_ to wait for device events.
   void DevicePollTask(bool poll_device);
 
+  // A processed frame is ready.
+  void FrameReady(const FrameReadyCB& cb, int output_buffer_index);
+
   // Size and format-related members remain constant after initialization.
   // The visible/allocated sizes of the input frame.
   gfx::Size input_visible_size_;
@@ -175,8 +181,16 @@
   // Error callback to the client.
   base::Closure error_cb_;
 
-  // Weak factory for producing weak pointers on the device_thread_
-  base::WeakPtrFactory<V4L2ImageProcessor> device_weak_factory_;
+  // WeakPtr<> pointing to |this| for use in posting tasks from the device
+  // worker threads back to the child thread.  Because the worker threads
+  // are members of this class, any task running on those threads is guaranteed
+  // that this object is still alive.  As a result, tasks posted from the child
+  // thread to the device thread should use base::Unretained(this),
+  // and tasks posted the other way should use |weak_this_|.
+  base::WeakPtr<V4L2ImageProcessor> weak_this_;
+
+  // Weak factory for producing weak pointers on the child thread.
+  base::WeakPtrFactory<V4L2ImageProcessor> weak_this_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(V4L2ImageProcessor);
 };
diff --git a/content/common/gpu_host_messages.h b/content/common/gpu_host_messages.h
index d9c7846..0705be0 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 55383876..24742a3 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/latency_info/latency_info.h"
+#include "ui/events/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 6f3dc1b8..58485e13 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/latency_info/latency_info.h"
+#include "ui/events/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 f7510d967..565b66f 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 namespace content {
 
diff --git a/content/common/input_messages.h b/content/common/input_messages.h
index 2a4b521..e83a77b 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/content.gyp b/content/content.gyp
index 2221d03..6160fb2 100644
--- a/content/content.gyp
+++ b/content/content.gyp
@@ -462,7 +462,6 @@
             '../device/usb/usb.gyp:device_usb_java',
             '../device/vibration/vibration.gyp:device_vibration_java',
             '../media/media.gyp:media_java',
-            '../mojo/mojo_base.gyp:mojo_application_bindings',
             '../mojo/mojo_base.gyp:mojo_system_java',
             '../mojo/mojo_public.gyp:mojo_bindings_java',
             '../net/net.gyp:net',
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index e04c79b..efcc6e5f 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -24,20 +24,20 @@
     '../gpu/gpu.gyp:gpu',
     '../gpu/gpu.gyp:gpu_ipc_client',
     '../gpu/gpu.gyp:gpu_ipc_common',
-    '../mojo/mojo_base.gyp:mojo_application_base',
     '../mojo/mojo_base.gyp:mojo_geometry_lib',
     '../mojo/mojo_base.gyp:mojo_url_type_converters',
-    '../mojo/mojo_base.gyp:tracing_service',
-    '../mojo/mojo_base.gyp:tracing_service_lib',
     '../mojo/mojo_public.gyp:mojo_cpp_bindings',
     '../mojo/mojo_public.gyp:mojo_js_bindings',
-    '../mojo/mojo_shell.gyp:mojo_runner_common_lib',
-    '../mojo/mojo_shell.gyp:mojo_runner_host_lib',
-    '../mojo/mojo_shell.gyp:mojo_shell_lib',
     '../net/net.gyp:http_server',
     '../net/net.gyp:net',
     '../net/net.gyp:net_extras',
     '../sandbox/sandbox.gyp:sandbox',
+    '../services/shell/shell.gyp:shell_lib',
+    '../services/shell/shell.gyp:shell_public',
+    '../services/shell/shell.gyp:shell_runner_common_lib',
+    '../services/shell/shell.gyp:shell_runner_host_lib',
+    '../services/tracing/tracing.gyp:tracing_lib',
+    '../services/tracing/tracing.gyp:tracing_public',
     '../skia/skia.gyp:skia',
     '../skia/skia.gyp:skia_mojo',
     '../sql/sql.gyp:sql',
@@ -63,7 +63,6 @@
     '../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',
diff --git a/content/content_child.gypi b/content/content_child.gypi
index 02e2137..f4ac67d 100644
--- a/content/content_child.gypi
+++ b/content/content_child.gypi
@@ -11,7 +11,7 @@
     '../ipc/ipc.gyp:ipc',
     '../mojo/mojo_base.gyp:mojo_common_lib',
     '../mojo/mojo_public.gyp:mojo_message_pump_lib',
-    '../mojo/mojo_shell.gyp:mojo_runner_common_lib',
+    '../services/shell/shell.gyp:shell_runner_common_lib',
     '../skia/skia.gyp:skia',
     '../storage/storage_common.gyp:storage_common',
     '../third_party/WebKit/public/blink.gyp:blink',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index e882cc3..1ae5f116 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -30,11 +30,11 @@
     '../media/gpu/ipc/media_ipc.gyp:media_gpu_ipc_client',
     '../media/gpu/ipc/media_ipc.gyp:media_gpu_ipc_common',
     '../media/midi/midi.gyp:midi',
-    '../mojo/mojo_base.gyp:mojo_application_bindings',
     '../mojo/mojo_edk.gyp:mojo_system_impl',
     '../mojo/mojo_public.gyp:mojo_cpp_bindings',
-    '../mojo/mojo_shell.gyp:mojo_runner_common_lib',
     '../net/net.gyp:net',
+    '../services/shell/shell.gyp:shell_public',
+    '../services/shell/shell.gyp:shell_runner_common_lib',
     '../skia/skia.gyp:skia',
     '../storage/storage_common.gyp:storage_common',
     '../third_party/WebKit/public/blink.gyp:blink',
@@ -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/latency_info/latency_info.gyp:latency_info_ipc',
+    '../ui/events/events.gyp:events_ipc',
     '../ui/gfx/gfx.gyp:gfx',
     '../ui/gfx/gfx.gyp:gfx_geometry',
     '../ui/gfx/ipc/gfx_ipc.gyp:gfx_ipc',
@@ -86,8 +86,8 @@
   ],
   'export_dependent_settings': [
     '../base/base.gyp:base',
-    '../mojo/mojo_base.gyp:mojo_application_bindings',
     '../mojo/mojo_public.gyp:mojo_cpp_bindings',
+    '../services/shell/shell.gyp:shell_public',
     # The public content API headers directly include Blink API headers, so we
     # have to export the blink header settings so that relative paths in these
     # headers resolve correctly.
diff --git a/content/content_common_mojo_bindings.gyp b/content/content_common_mojo_bindings.gyp
index 3b0c2fa..6e76e05 100644
--- a/content/content_common_mojo_bindings.gyp
+++ b/content/content_common_mojo_bindings.gyp
@@ -34,15 +34,11 @@
       },
       'dependencies': [
         '../components/leveldb/leveldb.gyp:leveldb_bindings_mojom',
-        '../mojo/mojo_base.gyp:mojo_application_bindings',
         '../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../services/shell/shell.gyp:shell_public',
         '../skia/skia.gyp:skia_mojo',
         '../third_party/WebKit/public/blink.gyp:mojo_bindings',
         '../ui/mojo/geometry/mojo_bindings.gyp:mojo_geometry_bindings',
-        '../url/url.gyp:url_interfaces_mojom',
-      ],
-      'export_dependent_settings': [
-        '../url/url.gyp:url_interfaces_mojom',
       ],
       'includes': [ '../mojo/mojom_bindings_generator_explicit.gypi' ],
     },
@@ -53,8 +49,12 @@
         'enable_wexit_time_destructors': 1,
       },
       'dependencies': [
+        '../url/url.gyp:url_mojom',
         'content_common_mojo_bindings_mojom',
       ],
+      'export_dependent_settings': [
+        '../url/url.gyp:url_mojom',
+      ],
     },
   ]
 }
diff --git a/content/content_renderer.gypi b/content/content_renderer.gypi
index 3e2500b..7c43fb9 100644
--- a/content/content_renderer.gypi
+++ b/content/content_renderer.gypi
@@ -22,11 +22,11 @@
     '../jingle/jingle.gyp:jingle_glue',
     '../media/blink/media_blink.gyp:media_blink',
     '../media/media.gyp:media',
-    '../mojo/mojo_base.gyp:mojo_application_bindings',
     '../mojo/mojo_base.gyp:mojo_geometry_lib',
     '../mojo/mojo_base.gyp:mojo_url_type_converters',
     '../mojo/mojo_edk.gyp:mojo_js_lib',
     '../net/net.gyp:net',
+    '../services/shell/shell.gyp:shell_public',
     '../skia/skia.gyp:skia',
     '../skia/skia.gyp:skia_mojo',
     '../storage/storage_common.gyp:storage_common',
diff --git a/content/content_resources.grd b/content/content_resources.grd
index 76fc7498..c7692b6 100644
--- a/content/content_resources.grd
+++ b/content/content_resources.grd
@@ -27,7 +27,7 @@
       <include name="IDR_INDEXED_DB_INTERNALS_CSS" file="browser/resources/indexed_db/indexeddb_internals.css" flattenhtml="true" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_HTML" file="browser/resources/media/media_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
       <include name="IDR_MEDIA_INTERNALS_JS" file="browser/resources/media/media_internals.js" flattenhtml="true" type="BINDATA" />
-      <include name="IDR_MOJO_CATALOG_MANIFEST" file="../mojo/services/catalog/manifest.json" type="BINDATA" />
+      <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_NETWORK_ERROR_LISTING_HTML" file="browser/resources/net/network_errors_listing.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
diff --git a/content/content_resources.gypi b/content/content_resources.gypi
index 01d3d03..0838f756 100644
--- a/content/content_resources.gypi
+++ b/content/content_resources.gypi
@@ -32,7 +32,7 @@
         },
       ],
       'dependencies': [
-        '<(DEPTH)/mojo/mojo_shell.gyp:mojo_catalog_manifest',
+        '<(DEPTH)/services/shell/shell.gyp:catalog_manifest',
         'content_app_browser_manifest',
         'content_app_renderer_manifest',
       ],
diff --git a/content/content_tests.gypi b/content/content_tests.gypi
index fcefea6..00adfe5 100644
--- a/content/content_tests.gypi
+++ b/content/content_tests.gypi
@@ -844,7 +844,6 @@
         '../media/media.gyp:media',
         '../media/midi/midi.gyp:midi',
         '../mojo/mojo_edk.gyp:mojo_common_test_support',
-        '../mojo/mojo_base.gyp:mojo_application_base',
         '../mojo/mojo_edk.gyp:mojo_system_impl',
         '../mojo/mojo_public.gyp:mojo_cpp_bindings',
         '../net/net.gyp:net_test_support',
@@ -852,6 +851,7 @@
         '../ppapi/ppapi_internal.gyp:ppapi_proxy',
         '../ppapi/ppapi_internal.gyp:ppapi_shared',
         '../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
+        '../services/shell/shell.gyp:shell_public',
         '../skia/skia.gyp:skia',
         '../storage/storage_browser.gyp:storage',
         '../storage/storage_common.gyp:storage_common',
@@ -870,7 +870,6 @@
         '../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',
@@ -1382,7 +1381,6 @@
         '../ipc/ipc.gyp:test_support_ipc',
         '../media/media.gyp:media_test_support',
         '../media/media.gyp:shared_memory_support',
-        '../mojo/mojo_base.gyp:mojo_application_base',
         '../mojo/mojo_base.gyp:mojo_test_support',
         '../mojo/mojo_edk.gyp:mojo_common_test_support',
         '../mojo/mojo_edk.gyp:mojo_system_impl',
@@ -1394,6 +1392,7 @@
         '../ppapi/ppapi_internal.gyp:ppapi_proxy',
         '../ppapi/ppapi_internal.gyp:ppapi_shared',
         '../ppapi/ppapi_internal.gyp:ppapi_unittest_shared',
+        '../services/shell/shell.gyp:shell_public',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/WebKit/public/blink.gyp:blink',
diff --git a/content/content_utility.gypi b/content/content_utility.gypi
index a826636..7d05b35d 100644
--- a/content/content_utility.gypi
+++ b/content/content_utility.gypi
@@ -6,12 +6,11 @@
   'dependencies': [
     '../base/base.gyp:base',
     '../courgette/courgette.gyp:courgette_lib',
-    '../mojo/mojo_base.gyp:mojo_application_base',
-    '../mojo/mojo_base.gyp:mojo_application_bindings',
     '../mojo/mojo_base.gyp:mojo_common_lib',
     '../mojo/mojo_public.gyp:mojo_cpp_bindings',
     '../mojo/mojo_public.gyp:mojo_message_pump_lib',
-    '../mojo/mojo_shell.gyp:mojo_shell_lib',
+    '../services/shell/shell.gyp:shell_public',
+    '../services/shell/shell.gyp:shell_lib',
     '../url/url.gyp:url_lib',
   ],
   'variables': {
diff --git a/content/gpu/BUILD.gn b/content/gpu/BUILD.gn
index 35fc15e..75ea4c58 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/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
index 3dfba0c..a24a1f4b 100644
--- a/content/gpu/gpu_main.cc
+++ b/content/gpu/gpu_main.cc
@@ -184,6 +184,7 @@
 #if defined(OS_WIN)
   // Use a UI message loop because ANGLE and the desktop GL platform can
   // create child windows to render to.
+  base::MessagePumpForGpu::InitFactory();
   base::MessageLoop main_message_loop(base::MessageLoop::TYPE_UI);
 #elif defined(OS_LINUX) && defined(USE_X11)
   // We need a UI loop so that we can grab the Expose events. See GLSurfaceGLX
diff --git a/content/public/test/browser_test_utils.cc b/content/public/test/browser_test_utils.cc
index a76aa30..0fc10f6 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/latency_info/latency_info.h"
+#include "ui/events/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 a0d4daf7..4b1eaca 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 02f7d8d6..0eb2d147 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/latency_info/latency_info.h"
+#include "ui/events/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 7914eea0..e407428 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/mus/BUILD.gn b/content/renderer/mus/BUILD.gn
index 326748f..c2d3f93 100644
--- a/content/renderer/mus/BUILD.gn
+++ b/content/renderer/mus/BUILD.gn
@@ -33,6 +33,5 @@
     "//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 0ae3a84..57cdb76d 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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 namespace {
 
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index d25ebf1..cc7ce3c5 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/extensions/extensions_tests.gyp b/extensions/extensions_tests.gyp
index bd131e02..e9bca65 100644
--- a/extensions/extensions_tests.gyp
+++ b/extensions/extensions_tests.gyp
@@ -26,10 +26,10 @@
         '../device/hid/hid.gyp:device_hid',
         '../device/serial/serial.gyp:device_serial',
         '../device/serial/serial.gyp:device_serial_test_util',
-        '../mojo/mojo_base.gyp:mojo_application_bindings',
         '../mojo/mojo_edk.gyp:mojo_js_lib',
         '../mojo/mojo_edk.gyp:mojo_system_impl',
         '../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../services/shell/shell.gyp:shell_public',
         '../testing/gmock.gyp:gmock',
         '../testing/gtest.gyp:gtest',
         '../third_party/leveldatabase/leveldatabase.gyp:leveldatabase',
diff --git a/gpu/gpu_ipc_client.gypi b/gpu/gpu_ipc_client.gypi
index 0aa89005..6ca3c0e0 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 05e7c44b..9e9ea60 100644
--- a/gpu/gpu_ipc_common.gypi
+++ b/gpu/gpu_ipc_common.gypi
@@ -8,10 +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_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 8a8b63618..8865814 100644
--- a/gpu/gpu_ipc_service.gypi
+++ b/gpu/gpu_ipc_service.gypi
@@ -6,10 +6,11 @@
   '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 2c0f88d..f77d1fe 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 e90ac2e..45e1d3de 100644
--- a/gpu/ipc/client/DEPS
+++ b/gpu/ipc/client/DEPS
@@ -1,5 +1,6 @@
 include_rules = [
   "+base",
   "+ipc",
-  "+ui/latency_info",
+  "+ui/events",
+  "+ui/base",
 ]
diff --git a/gpu/ipc/client/command_buffer_proxy_impl.h b/gpu/ipc/client/command_buffer_proxy_impl.h
index 7a200de..89347bf 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 f2c27e1..be04133 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 2c31f72..c596e26 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 04878b14..45e1d3de 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 0e5ed72..449d151 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 9ad2c9cd..7f022f8 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 facf83e..0461b20 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/latency_info",
+  "+ui/events",
   "+ui/ozone",
 ]
diff --git a/gpu/ipc/service/gpu_channel_manager_delegate.h b/gpu/ipc/service/gpu_channel_manager_delegate.h
index 803e011..83f2dc11 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 3b4992b..9d17603 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 a8c4600..e455cf00 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 4c8f927..b63194a7 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/ios/chrome/browser/DEPS b/ios/chrome/browser/DEPS
index 7a35c957..838606e 100644
--- a/ios/chrome/browser/DEPS
+++ b/ios/chrome/browser/DEPS
@@ -102,5 +102,6 @@
   # Strings and resources.
   "+components/grit",
   "+components/strings/grit",
+  "+grit/components_strings.h",
   "+ios/chrome/grit",
 ]
diff --git a/ios/chrome/browser/passwords/credential_manager.h b/ios/chrome/browser/passwords/credential_manager.h
index da6c4d6..68dcf72 100644
--- a/ios/chrome/browser/passwords/credential_manager.h
+++ b/ios/chrome/browser/passwords/credential_manager.h
@@ -58,9 +58,11 @@
   bool IsZeroClickAllowed() const override;
   GURL GetOrigin() const override;
   void SendCredential(
-      int id,
+      const password_manager::SendCredentialCallback& send_callback,
       const password_manager::CredentialInfo& credential) override;
-  void SendPasswordForm(int id, const autofill::PasswordForm* form) override;
+  void SendPasswordForm(
+      const password_manager::SendCredentialCallback& send_callback,
+      const autofill::PasswordForm* form) override;
   password_manager::PasswordManagerClient* client() const override;
   autofill::PasswordForm GetSynthesizedFormForOrigin() const override;
 
@@ -84,6 +86,9 @@
     ERROR_TYPE_SECURITY_ERROR_UNTRUSTED_ORIGIN,
   };
 
+  void SendCredentialByID(int request_id,
+                          const password_manager::CredentialInfo& credential);
+
   // Sends a message via |js_manager_| to resolve the JavaScript Promise
   // associated with |request_id|. Invoked after a page-initiated credential
   // event is acknowledged by the PasswordStore.
diff --git a/ios/chrome/browser/passwords/credential_manager.mm b/ios/chrome/browser/passwords/credential_manager.mm
index b1e86fd..1389ebae 100644
--- a/ios/chrome/browser/passwords/credential_manager.mm
+++ b/ios/chrome/browser/passwords/credential_manager.mm
@@ -117,7 +117,7 @@
   // Invoked when the page invokes navigator.credentials.request(), this
   // function will attempt to retrieve a Credential from the PasswordStore that
   // meets the specified parameters and, if successful, send it back to the page
-  // via SendCredential.
+  // via SendCredentialByID.
   DCHECK_GE(request_id, 0);
   password_manager::PasswordStore* store = GetPasswordStore();
 
@@ -139,7 +139,7 @@
   // available, send back an empty credential.
   if (zero_click_only && !IsZeroClickAllowed()) {
     base::MessageLoop::current()->PostTask(
-        FROM_HERE, base::Bind(&CredentialManager::SendCredential,
+        FROM_HERE, base::Bind(&CredentialManager::SendCredentialByID,
                               weak_factory_.GetWeakPtr(), request_id,
                               password_manager::CredentialInfo()));
     return;
@@ -161,8 +161,9 @@
   std::vector<std::string> realms;
   pending_request_.reset(
       new password_manager::CredentialManagerPendingRequestTask(
-          this, request_id, zero_click_only, page_url, true, federation_urls,
-          realms));
+          this, base::Bind(&CredentialManager::SendCredentialByID,
+                           base::Unretained(this), request_id),
+          zero_click_only, page_url, true, federation_urls, realms));
   store->GetAutofillableLogins(pending_request_.get());
 }
 
@@ -269,6 +270,12 @@
 }
 
 void CredentialManager::SendCredential(
+    const password_manager::SendCredentialCallback& send_callback,
+    const password_manager::CredentialInfo& credential) {
+  send_callback.Run(credential);
+}
+
+void CredentialManager::SendCredentialByID(
     int request_id,
     const password_manager::CredentialInfo& credential) {
   // Invoked when the asynchronous interaction with the PasswordStore completes,
@@ -284,8 +291,9 @@
                 }];
 }
 
-void CredentialManager::SendPasswordForm(int request_id,
-                                         const autofill::PasswordForm* form) {
+void CredentialManager::SendPasswordForm(
+    const password_manager::SendCredentialCallback& send_callback,
+    const autofill::PasswordForm* form) {
   password_manager::CredentialInfo info;
   if (form) {
     password_manager::CredentialType type_to_return =
@@ -295,7 +303,7 @@
     info = password_manager::CredentialInfo(*form, type_to_return);
     // TODO(vasilii): update |skip_zero_click| in the store (crbug.com/594110).
   }
-  SendCredential(request_id, info);
+  SendCredential(send_callback, info);
 }
 
 password_manager::PasswordManagerClient* CredentialManager::client() const {
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.h b/ios/chrome/browser/ssl/ios_ssl_blocking_page.h
index c653a5e..2dac5de 100644
--- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.h
+++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.h
@@ -50,6 +50,7 @@
   void CommandReceived(const std::string& command) override;
   void OnProceed() override;
   void OnDontProceed() override;
+  void OverrideItem(web::NavigationItem* item) override;
 
   // SecurityInterstitialPage implementation:
   bool ShouldCreateNewNavigation() const override;
diff --git a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
index 659711e..d283a95 100644
--- a/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
+++ b/ios/chrome/browser/ssl/ios_ssl_blocking_page.mm
@@ -12,11 +12,15 @@
 #include "base/strings/utf_string_conversions.h"
 #include "components/security_interstitials/core/metrics_helper.h"
 #include "components/security_interstitials/core/ssl_error_ui.h"
+#include "grit/components_strings.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/interstitials/ios_chrome_controller_client.h"
 #include "ios/chrome/browser/interstitials/ios_chrome_metrics_helper.h"
 #include "ios/chrome/grit/ios_strings.h"
 #include "ios/public/provider/chrome/browser/browser_constants.h"
+#include "ios/web/public/cert_store.h"
+#import "ios/web/public/navigation_item.h"
+#include "ios/web/public/ssl_status.h"
 #include "ios/web/public/web_state/web_state.h"
 #include "net/base/net_errors.h"
 #include "ui/base/l10n/l10n_util.h"
@@ -180,6 +184,19 @@
   NotifyDenyCertificate();
 }
 
+void IOSSSLBlockingPage::OverrideItem(web::NavigationItem* item) {
+  item->SetTitle(l10n_util::GetStringUTF16(IDS_SSL_V2_TITLE));
+
+  item->GetSSL().security_style = web::SECURITY_STYLE_AUTHENTICATION_BROKEN;
+  item->GetSSL().cert_status = ssl_info_.cert_status;
+  // On iOS cert may be null when it is not provided by API callback or can not
+  // be parsed.
+  if (ssl_info_.cert) {
+    item->GetSSL().cert_id = web::CertStore::GetInstance()->StoreCert(
+        ssl_info_.cert.get(), web_state()->GetCertGroupId());
+  }
+}
+
 void IOSSSLBlockingPage::NotifyDenyCertificate() {
   // It's possible that callback_ may not exist if the user clicks "Proceed"
   // followed by pressing the back button before the interstitial is hidden.
diff --git a/ios/chrome/browser/ui/webui/history/history_ui.cc b/ios/chrome/browser/ui/webui/history/history_ui.cc
index dd4e5bd..aa00f05 100644
--- a/ios/chrome/browser/ui/webui/history/history_ui.cc
+++ b/ios/chrome/browser/ui/webui/history/history_ui.cc
@@ -16,7 +16,6 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
 #include "ios/chrome/browser/chrome_switches.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
-#include "ios/chrome/browser/history/web_history_service_factory.h"
 #include "ios/chrome/browser/signin/signin_manager_factory.h"
 #include "ios/chrome/browser/ui/webui/history/browsing_history_handler.h"
 #include "ios/chrome/browser/ui/webui/history/metrics_handler.h"
@@ -88,8 +87,6 @@
                              IDS_HISTORY_ACTION_MENU_DESCRIPTION);
   source->AddLocalizedString("removeFromHistory", IDS_HISTORY_REMOVE_PAGE);
   source->AddLocalizedString("moreFromSite", IDS_HISTORY_MORE_FROM_SITE);
-  source->AddLocalizedString("groupByDomainLabel",
-                             IDS_HISTORY_GROUP_BY_DOMAIN_LABEL);
   source->AddLocalizedString("rangeLabel", IDS_HISTORY_RANGE_LABEL);
   source->AddLocalizedString("rangeAllTime", IDS_HISTORY_RANGE_ALL_TIME);
   source->AddLocalizedString("rangeWeek", IDS_HISTORY_RANGE_WEEK);
@@ -98,11 +95,7 @@
   source->AddLocalizedString("rangeNext", IDS_HISTORY_RANGE_NEXT);
   source->AddLocalizedString("rangePrevious", IDS_HISTORY_RANGE_PREVIOUS);
   source->AddLocalizedString("numberVisits", IDS_HISTORY_NUMBER_VISITS);
-  source->AddLocalizedString("filterAllowed", IDS_HISTORY_FILTER_ALLOWED);
   source->AddLocalizedString("filterBlocked", IDS_HISTORY_FILTER_BLOCKED);
-  source->AddLocalizedString("inContentPack", IDS_HISTORY_IN_CONTENT_PACK);
-  source->AddLocalizedString("allowItems", IDS_HISTORY_FILTER_ALLOW_ITEMS);
-  source->AddLocalizedString("blockItems", IDS_HISTORY_FILTER_BLOCK_ITEMS);
   source->AddLocalizedString("blockedVisitText",
                              IDS_HISTORY_BLOCKED_VISIT_TEXT);
   source->AddLocalizedString("hasSyncedResults",
@@ -115,9 +108,6 @@
   source->AddLocalizedString("cancel", IDS_CANCEL);
   source->AddLocalizedString("deleteConfirm",
                              IDS_HISTORY_DELETE_PRIOR_VISITS_CONFIRM_BUTTON);
-  source->AddBoolean(
-      "isFullHistorySyncEnabled",
-      ios::WebHistoryServiceFactory::GetForBrowserState(browser_state) != NULL);
   bool group_by_domain = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kHistoryEnableGroupByDomain);
   source->AddBoolean("groupByDomain", group_by_domain);
diff --git a/ios/web/interstitials/web_interstitial_impl.mm b/ios/web/interstitials/web_interstitial_impl.mm
index cbca86c..e0cf6f0 100644
--- a/ios/web/interstitials/web_interstitial_impl.mm
+++ b/ios/web/interstitials/web_interstitial_impl.mm
@@ -61,6 +61,9 @@
     CRWSessionController* sessionController =
         navigation_manager_->GetSessionController();
     [sessionController addTransientEntryWithURL:url_];
+
+    // Give delegates a chance to set some states on the navigation item.
+    GetDelegate()->OverrideItem(navigation_manager_->GetTransientItem());
   }
 }
 
diff --git a/ios/web/public/interstitials/web_interstitial_delegate.h b/ios/web/public/interstitials/web_interstitial_delegate.h
index e754d51a..6b6c3e02 100644
--- a/ios/web/public/interstitials/web_interstitial_delegate.h
+++ b/ios/web/public/interstitials/web_interstitial_delegate.h
@@ -12,6 +12,8 @@
 
 namespace web {
 
+class NavigationItem;
+
 // Superclass for delegates that provide data to a WebInterstitial.  After the
 // WebInterstitial is shown, it takes ownership of its delegate.
 class WebInterstitialDelegate {
@@ -23,6 +25,13 @@
   // on WebInterstitial, since navigations etc may cancel them.
   virtual void OnProceed() {}
   virtual void OnDontProceed() {}
+
+  // Called with the NavigationItem that is going to be added to the navigation
+  // manager.
+  // Gives an opportunity to delegates to set states on the |item|.
+  // Note that this is only called if the WebInterstitial was constructed with
+  // |new_navigation| set to true.
+  virtual void OverrideItem(NavigationItem* item) {}
 };
 
 // Provides HTML to an HTMLWebInterstitialImpl.
diff --git a/ios/web/public/test/test_web_state.h b/ios/web/public/test/test_web_state.h
index d3f6772..4506a1d 100644
--- a/ios/web/public/test/test_web_state.h
+++ b/ios/web/public/test/test_web_state.h
@@ -45,6 +45,7 @@
   CRWWebViewProxyType GetWebViewProxy() const override;
   bool IsShowingWebInterstitial() const override;
   WebInterstitial* GetWebInterstitial() const override;
+  int GetCertGroupId() const override;
   void AddObserver(WebStateObserver* observer) override {}
   void RemoveObserver(WebStateObserver* observer) override {}
   void AddPolicyDecider(WebStatePolicyDecider* decider) override {}
diff --git a/ios/web/public/test/test_web_state.mm b/ios/web/public/test/test_web_state.mm
index bb577bd7..ebd739e0 100644
--- a/ios/web/public/test/test_web_state.mm
+++ b/ios/web/public/test/test_web_state.mm
@@ -62,6 +62,10 @@
   return nullptr;
 }
 
+int TestWebState::GetCertGroupId() const {
+  return 0;
+}
+
 void TestWebState::SetContentIsHTML(bool content_is_html) {
   content_is_html_ = content_is_html;
 }
diff --git a/ios/web/public/web_state/web_state.h b/ios/web/public/web_state/web_state.h
index de9f0a00..667c8af 100644
--- a/ios/web/public/web_state/web_state.h
+++ b/ios/web/public/web_state/web_state.h
@@ -151,6 +151,9 @@
   // Returns the currently visible WebInterstitial if one is shown.
   virtual WebInterstitial* GetWebInterstitial() const = 0;
 
+  // Returns the unique ID to use with web::CertStore.
+  virtual int GetCertGroupId() const = 0;
+
   // Callback used to handle script commands.
   // The callback must return true if the command was handled, and false
   // otherwise.
diff --git a/ios/web/web_state/web_state_impl.h b/ios/web/web_state/web_state_impl.h
index 9d5578aa..6cf970d 100644
--- a/ios/web/web_state/web_state_impl.h
+++ b/ios/web/web_state/web_state_impl.h
@@ -233,6 +233,7 @@
   void ShowTransientContentView(CRWContentView* content_view) override;
   bool IsShowingWebInterstitial() const override;
   WebInterstitial* GetWebInterstitial() const override;
+  int GetCertGroupId() const override;
   void AddScriptCommandCallback(const ScriptCommandCallback& callback,
                                 const std::string& command_prefix) override;
   void RemoveScriptCommandCallback(const std::string& command_prefix) override;
diff --git a/ios/web/web_state/web_state_impl.mm b/ios/web/web_state/web_state_impl.mm
index 30a9793..13d104d 100644
--- a/ios/web/web_state/web_state_impl.mm
+++ b/ios/web/web_state/web_state_impl.mm
@@ -298,6 +298,10 @@
   return interstitial_;
 }
 
+int WebStateImpl::GetCertGroupId() const {
+  return request_tracker_->identifier();
+}
+
 net::HttpResponseHeaders* WebStateImpl::GetHttpResponseHeaders() const {
   return http_response_headers_.get();
 }
diff --git a/ipc/ipc_message_start.h b/ipc/ipc_message_start.h
index c3abddc0..ea1f7b998 100644
--- a/ipc/ipc_message_start.h
+++ b/ipc/ipc_message_start.h
@@ -101,7 +101,6 @@
   OzoneGpuMsgStart,
   ChromeUtilityExtensionsMsgStart,
   PlatformNotificationMsgStart,
-  CredentialManagerMsgStart,
   PDFMsgStart,
   ManifestManagerMsgStart,
   ExtensionUtilityMsgStart,
diff --git a/mash/DEPS b/mash/DEPS
index c420e062..27093b9 100644
--- a/mash/DEPS
+++ b/mash/DEPS
@@ -3,13 +3,12 @@
   "+components/mus/common/util.h",
   "+components/mus/public",
   "+components/prefs",
-  "+services/shell",
   "+mojo/common",
   "+mojo/converters",
   "+mojo/public",
-  "+mojo/services/catalog/public",
-  "+mojo/services/network/public",
-  "+mojo/services/tracing/public",
+  "+services/catalog/public",
+  "+services/shell",
+  "+services/tracing/public",
   "+third_party/skia/include",
   "+ui",
 ]
diff --git a/mash/example/views_examples/BUILD.gn b/mash/example/views_examples/BUILD.gn
index 5c0fc56..1913237f 100644
--- a/mash/example/views_examples/BUILD.gn
+++ b/mash/example/views_examples/BUILD.gn
@@ -22,9 +22,9 @@
     "//components/mus/public/interfaces",
     "//mojo/converters/geometry",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
     "//services/shell/public/cpp:sources",
+    "//services/tracing/public/cpp",
     "//skia",
     "//ui/gfx",
     "//ui/gfx/geometry",
diff --git a/mash/example/views_examples/views_examples_application_delegate.h b/mash/example/views_examples/views_examples_application_delegate.h
index a268420..2d348a01 100644
--- a/mash/example/views_examples/views_examples_application_delegate.h
+++ b/mash/example/views_examples/views_examples_application_delegate.h
@@ -8,8 +8,8 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace views {
 class AuraInit;
diff --git a/mash/init/BUILD.gn b/mash/init/BUILD.gn
index 7aae0fb..8d9cd128 100644
--- a/mash/init/BUILD.gn
+++ b/mash/init/BUILD.gn
@@ -23,8 +23,8 @@
     "//mash/init/public/interfaces",
     "//mash/login/public/interfaces",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
   ]
 
   data_deps = [
diff --git a/mash/login/BUILD.gn b/mash/login/BUILD.gn
index 22ca0d4..f74e781 100644
--- a/mash/login/BUILD.gn
+++ b/mash/login/BUILD.gn
@@ -22,8 +22,8 @@
     "//mash/login/public/interfaces",
     "//mash/wm/public/interfaces",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//ui/views",
     "//ui/views/mus:for_mojo_application",
   ]
diff --git a/mash/login/login.cc b/mash/login/login.cc
index 2d64a8a..5e63ca3 100644
--- a/mash/login/login.cc
+++ b/mash/login/login.cc
@@ -17,9 +17,9 @@
 #include "mash/login/public/interfaces/login.mojom.h"
 #include "mash/wm/public/interfaces/container.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/label_button.h"
 #include "ui/views/mus/aura_init.h"
diff --git a/mash/quick_launch/BUILD.gn b/mash/quick_launch/BUILD.gn
index b0fc1fe..93487af4 100644
--- a/mash/quick_launch/BUILD.gn
+++ b/mash/quick_launch/BUILD.gn
@@ -17,10 +17,10 @@
   deps = [
     "//base",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/catalog/public/interfaces",
-    "//mojo/services/tracing/public/cpp",
+    "//services/catalog/public/interfaces",
     "//services/shell/public/cpp",
     "//services/shell/public/interfaces",
+    "//services/tracing/public/cpp",
     "//ui/views",
     "//ui/views/mus:for_mojo_application",
     "//url",
diff --git a/mash/quick_launch/quick_launch_application.cc b/mash/quick_launch/quick_launch_application.cc
index aff17cc..3c36329 100644
--- a/mash/quick_launch/quick_launch_application.cc
+++ b/mash/quick_launch/quick_launch_application.cc
@@ -10,10 +10,10 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/c/system/main.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/application_runner.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/textfield/textfield.h"
 #include "ui/views/controls/textfield/textfield_controller.h"
diff --git a/mash/quick_launch/quick_launch_application.h b/mash/quick_launch/quick_launch_application.h
index c5e5c76..46a43fff 100644
--- a/mash/quick_launch/quick_launch_application.h
+++ b/mash/quick_launch/quick_launch_application.h
@@ -8,9 +8,9 @@
 #include <memory>
 
 #include "base/macros.h"
-#include "mojo/services/catalog/public/interfaces/catalog.mojom.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace views {
 class AuraInit;
diff --git a/mash/screenlock/BUILD.gn b/mash/screenlock/BUILD.gn
index abb9faf87..3b9e453 100644
--- a/mash/screenlock/BUILD.gn
+++ b/mash/screenlock/BUILD.gn
@@ -22,9 +22,9 @@
     "//mash/wm/public/interfaces",
     "//mojo/common",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
     "//services/shell/public/cpp:sources",
+    "//services/tracing/public/cpp",
     "//ui/views",
     "//ui/views/mus:for_mojo_application",
   ]
diff --git a/mash/screenlock/screenlock.h b/mash/screenlock/screenlock.h
index 5dace7d..1d770811 100644
--- a/mash/screenlock/screenlock.h
+++ b/mash/screenlock/screenlock.h
@@ -11,8 +11,8 @@
 #include "base/macros.h"
 #include "mash/session/public/interfaces/session.mojom.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace views {
 class AuraInit;
diff --git a/mash/task_viewer/BUILD.gn b/mash/task_viewer/BUILD.gn
index e2208ef..1a1b7b7 100644
--- a/mash/task_viewer/BUILD.gn
+++ b/mash/task_viewer/BUILD.gn
@@ -16,11 +16,11 @@
   deps = [
     "//base",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/catalog/public/interfaces",
-    "//mojo/services/tracing/public/cpp",
+    "//services/catalog/public/interfaces",
     "//services/shell/public/cpp",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
+    "//services/tracing/public/cpp",
     "//ui/resources",
     "//ui/views",
     "//ui/views/mus:for_mojo_application",
diff --git a/mash/task_viewer/task_viewer.cc b/mash/task_viewer/task_viewer.cc
index b6112de..eaa6a617 100644
--- a/mash/task_viewer/task_viewer.cc
+++ b/mash/task_viewer/task_viewer.cc
@@ -15,7 +15,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/connector.h"
 #include "services/shell/public/interfaces/shell.mojom.h"
diff --git a/mash/task_viewer/task_viewer.h b/mash/task_viewer/task_viewer.h
index de0976c..d3cb636 100644
--- a/mash/task_viewer/task_viewer.h
+++ b/mash/task_viewer/task_viewer.h
@@ -10,8 +10,8 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace views {
 class AuraInit;
diff --git a/mash/wm/BUILD.gn b/mash/wm/BUILD.gn
index 917a9da2..5ef347d 100644
--- a/mash/wm/BUILD.gn
+++ b/mash/wm/BUILD.gn
@@ -72,8 +72,8 @@
     "//mojo/common:common_base",
     "//mojo/converters/geometry",
     "//mojo/converters/input_events",
-    "//mojo/services/tracing/public/cpp",
     "//services/shell/public/cpp",
+    "//services/tracing/public/cpp",
     "//skia",
     "//ui/aura",
     "//ui/events",
diff --git a/mash/wm/window_manager_application.cc b/mash/wm/window_manager_application.cc
index c2b0876..cf50eba 100644
--- a/mash/wm/window_manager_application.cc
+++ b/mash/wm/window_manager_application.cc
@@ -16,9 +16,9 @@
 #include "mash/wm/root_windows_observer.h"
 #include "mash/wm/user_window_controller_impl.h"
 #include "mojo/converters/input_events/input_events_type_converters.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/connector.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 #include "ui/events/event.h"
 #include "ui/mojo/init/ui_init.h"
 #include "ui/views/mus/aura_init.h"
diff --git a/mash/wm/window_manager_application.h b/mash/wm/window_manager_application.h
index e055b6c..ffa0e35 100644
--- a/mash/wm/window_manager_application.h
+++ b/mash/wm/window_manager_application.h
@@ -21,8 +21,8 @@
 #include "mash/wm/public/interfaces/user_window_controller.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 namespace ui {
 namespace mojo {
diff --git a/media/mojo/interfaces/mojo_bindings.gyp b/media/mojo/interfaces/mojo_bindings.gyp
index 6a57a53..3e3c6ac 100644
--- a/media/mojo/interfaces/mojo_bindings.gyp
+++ b/media/mojo/interfaces/mojo_bindings.gyp
@@ -17,8 +17,8 @@
       'type': 'static_library',
       'dependencies': [
         'platform_verification_mojo_bindings',
-        '../../../mojo/mojo_base.gyp:mojo_application_bindings',
         '../../../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../../../services/shell/shell.gyp:shell_public',
       ],
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/media/mojo/interfaces/platform_verification.mojom.cc',
@@ -39,8 +39,8 @@
       'type': 'static_library',
       'dependencies': [
         'provision_fetcher_mojo_bindings',
-        '../../../mojo/mojo_base.gyp:mojo_application_bindings',
         '../../../mojo/mojo_public.gyp:mojo_cpp_bindings',
+        '../../../services/shell/shell.gyp:shell_public',
       ],
       'sources': [
         '<(SHARED_INTERMEDIATE_DIR)/media/mojo/interfaces/provision_fetcher.mojom.cc',
diff --git a/mojo/BUILD.gn b/mojo/BUILD.gn
index 5483ff3..885166f 100644
--- a/mojo/BUILD.gn
+++ b/mojo/BUILD.gn
@@ -10,7 +10,6 @@
   deps = [
     ":tests",
     "//mojo/common",
-    "//mojo/services",
   ]
 
   if (!(is_linux && target_cpu == "x86")) {
diff --git a/mojo/common/DEPS b/mojo/common/DEPS
index 3cf60c15a..8daa768 100644
--- a/mojo/common/DEPS
+++ b/mojo/common/DEPS
@@ -9,9 +9,9 @@
 
 specific_include_rules = {
   "trace_controller_impl\.h": [
-    "+mojo/services/tracing/public/interfaces/tracing.mojom.h"
+    "+services/tracing/public/interfaces/tracing.mojom.h"
   ],
   "tracing_impl\.h": [
-    "+mojo/services/tracing/public/interfaces/tracing.mojom.h"
+    "+services/tracing/public/interfaces/tracing.mojom.h"
   ],
 }
diff --git a/mojo/mojo_base.gyp b/mojo/mojo_base.gyp
index 7eec79a..d209a4d 100644
--- a/mojo/mojo_base.gyp
+++ b/mojo/mojo_base.gyp
@@ -120,75 +120,6 @@
       ],
     },
     {
-      'target_name': 'mojo_application_bindings_mojom',
-      'type': 'none',
-      'variables': {
-        'mojom_files': [
-          'services/catalog/public/interfaces/catalog.mojom',
-          'services/catalog/public/interfaces/resolver.mojom',
-          '../services/shell/public/interfaces/capabilities.mojom',
-          '../services/shell/public/interfaces/connector.mojom',
-          '../services/shell/public/interfaces/interface_provider.mojom',
-          '../services/shell/public/interfaces/shell.mojom',
-          '../services/shell/public/interfaces/shell_client.mojom',
-          '../services/shell/public/interfaces/shell_client_factory.mojom',
-          '../services/shell/public/interfaces/shell_resolver.mojom',
-        ],
-      },
-      'includes': [ 'mojom_bindings_generator_explicit.gypi' ],
-    },
-    {
-      # GN version: //services/shell/public/cpp
-      'target_name': 'mojo_application_base',
-      'type': 'static_library',
-      'sources': [
-        '../services/shell/public/cpp/application_runner.h',
-        '../services/shell/public/cpp/capabilities.h',
-        '../services/shell/public/cpp/connect.h',
-        '../services/shell/public/cpp/connection.h',
-        '../services/shell/public/cpp/connector.h',
-        '../services/shell/public/cpp/identity.h',
-        '../services/shell/public/cpp/initialize_base_and_icu.cc',
-        '../services/shell/public/cpp/initialize_base_and_icu.h',
-        '../services/shell/public/cpp/interface_binder.h',
-        '../services/shell/public/cpp/interface_factory.h',
-        '../services/shell/public/cpp/interface_factory_impl.h',
-        '../services/shell/public/cpp/interface_registry.h',
-        '../services/shell/public/cpp/lib/application_runner.cc',
-        '../services/shell/public/cpp/lib/capabilities.cc',
-        '../services/shell/public/cpp/lib/connection_impl.cc',
-        '../services/shell/public/cpp/lib/connection_impl.h',
-        '../services/shell/public/cpp/lib/connector_impl.cc',
-        '../services/shell/public/cpp/lib/connector_impl.h',
-        '../services/shell/public/cpp/lib/identity.cc',
-        '../services/shell/public/cpp/lib/interface_factory_binder.h',
-        '../services/shell/public/cpp/lib/interface_registry.cc',
-        '../services/shell/public/cpp/lib/message_loop_ref.cc',
-        '../services/shell/public/cpp/lib/names.cc',
-        '../services/shell/public/cpp/lib/shell_client.cc',
-        '../services/shell/public/cpp/lib/shell_connection.cc',
-        '../services/shell/public/cpp/message_loop_ref.h',
-        '../services/shell/public/cpp/names.h',
-        '../services/shell/public/cpp/shell.h',
-        '../services/shell/public/cpp/shell_client.h',
-        '../services/shell/public/cpp/shell_connection.h',
-      ],
-      'dependencies': [
-        '../base/base.gyp:base_i18n',
-        'mojo_application_bindings',
-        'mojo_public.gyp:mojo_message_pump_lib',
-      ],
-    },
-    {
-      # GN version: //mojo/public/interfaces/application:application
-      'target_name': 'mojo_application_bindings',
-      'type': 'static_library',
-      'dependencies': [
-        'mojo_application_bindings_mojom',
-        'mojo_public.gyp:mojo_cpp_bindings',
-      ],
-    },
-    {
       # GN version: //mojo/test:test_support
       'target_name': 'mojo_test_support',
       'type': 'static_library',
@@ -201,60 +132,6 @@
         'test/test_utils_win.cc',
       ],
     },
-    {
-      # GN version: //services/shell/public/cpp/tests
-      'target_name': 'mojo_public_application_unittests',
-      'type': 'executable',
-      'dependencies': [
-        '../base/base.gyp:base',
-        '../testing/gtest.gyp:gtest',
-        'mojo_application_base',
-        'mojo_edk.gyp:mojo_run_all_unittests',
-      ],
-      'sources': [
-        '../services/shell/public/cpp/tests/interface_registry_unittest.cc',
-      ],
-    },
-    {
-      # Technically, these should be in the mojo_services.gyp, but this causes
-      # a cycle since the ios generator can't have gyp files refer to each
-      # other, even if the targets don't form a cycle.
-      #
-      # GN version: //mojo/services/tracing:lib
-      'target_name': 'tracing_service',
-      'type': 'static_library',
-      'dependencies': [
-        'mojo_services.gyp:tracing_service_bindings_lib',
-        'mojo_base.gyp:mojo_application_bindings',
-        'mojo_edk.gyp:mojo_system_impl',
-      ],
-      'sources': [
-        'services/tracing/trace_data_sink.cc',
-        'services/tracing/trace_data_sink.h',
-        'services/tracing/trace_recorder_impl.cc',
-        'services/tracing/trace_recorder_impl.h',
-        'services/tracing/tracing_app.cc',
-        'services/tracing/tracing_app.h',
-      ],
-    },
-    {
-      # GN version: //mojo/services/public/cpp
-      'target_name': 'tracing_service_lib',
-      'type': 'static_library',
-      'dependencies': [
-        'mojo_services.gyp:tracing_service_bindings_lib',
-        'mojo_base.gyp:mojo_application_bindings',
-        'mojo_edk.gyp:mojo_system_impl',
-      ],
-      'sources': [
-        'services/tracing/public/cpp/switches.cc',
-        'services/tracing/public/cpp/switches.h',
-        'services/tracing/public/cpp/tracing_impl.cc',
-        'services/tracing/public/cpp/tracing_impl.h',
-        'services/tracing/public/cpp/trace_provider_impl.cc',
-        'services/tracing/public/cpp/trace_provider_impl.h',
-      ],
-    },
   ],
   'conditions': [
     ['OS=="android"', {
diff --git a/mojo/mojo_services.gyp b/mojo/mojo_services.gyp
deleted file mode 100644
index 2ac03d0b..0000000
--- a/mojo/mojo_services.gyp
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [
-    {
-      'target_name': 'tracing_service_bindings_mojom',
-      'type': 'none',
-      'variables': {
-        'mojom_files': [
-          'services/tracing/public/interfaces/tracing.mojom',
-        ],
-        'mojom_include_path': '<(DEPTH)/mojo/services',
-      },
-      'includes': [
-        'mojom_bindings_generator_explicit.gypi',
-      ],
-    },
-    {
-      # GN version: //mojo/services/tracing/public/interfaces
-      'target_name': 'tracing_service_bindings_lib',
-      'type': 'static_library',
-      'dependencies': [
-        'tracing_service_bindings_mojom',
-      ],
-    },
-  ],
-}
diff --git a/mojo/mojo_shell.gyp b/mojo/mojo_shell.gyp
deleted file mode 100644
index f7e8949..0000000
--- a/mojo/mojo_shell.gyp
+++ /dev/null
@@ -1,164 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  'targets': [{
-    'target_name': 'mojo_shell_lib',
-    'type': 'static_library',
-    'sources': [
-      'services/catalog/catalog.cc',
-      'services/catalog/catalog.h',
-      'services/catalog/entry.cc',
-      'services/catalog/entry.h',
-      'services/catalog/factory.cc',
-      'services/catalog/factory.h',
-      'services/catalog/store.cc',
-      'services/catalog/store.h',
-      'services/catalog/types.h',
-      '../services/shell/loader.h',
-      '../services/shell/connect_params.cc',
-      '../services/shell/connect_params.h',
-      '../services/shell/connect_util.cc',
-      '../services/shell/connect_util.h',
-      '../services/shell/native_runner.h',
-      '../services/shell/native_runner_delegate.h',
-      '../services/shell/shell.cc',
-      '../services/shell/shell.h',
-      '../services/shell/switches.cc',
-      '../services/shell/switches.cc',
-      'util/filename_util.cc',
-      'util/filename_util.h',
-    ],
-    'dependencies': [
-      '<(DEPTH)/base/base.gyp:base',
-      '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
-      '<(DEPTH)/net/net.gyp:net',
-      '<(DEPTH)/url/url.gyp:url_lib',
-    ],
-    'export_dependent_settings': [
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-    ],
-  }, {
-    'target_name': 'mojo_shell_unittests',
-    'type': 'executable',
-    'sources': [
-      '../services/shell/tests/loader_unittest.cc',
-    ],
-    'dependencies': [
-      'mojo_shell_lib',
-      'mojo_shell_test_bindings',
-      '<(DEPTH)/base/base.gyp:base',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_base',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
-      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_run_all_unittests',
-      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
-      '<(DEPTH)/testing/gtest.gyp:gtest',
-      '<(DEPTH)/url/url.gyp:url_lib',
-    ]
-  }, {
-    'target_name': 'mojo_shell_test_bindings',
-    'type': 'static_library',
-    'variables': {
-      'mojom_files': [
-        '../services/shell/tests/test.mojom',
-      ],
-    },
-    'includes': [
-      'mojom_bindings_generator_explicit.gypi',
-    ],
-  }, {
-    'target_name': 'mojo_runner_common_lib',
-    'type': 'static_library',
-    'sources': [
-      '../services/shell/runner/common/client_util.cc',
-      '../services/shell/runner/common/client_util.h',
-      '../services/shell/runner/common/switches.cc',
-      '../services/shell/runner/common/switches.h',
-    ],
-    'include_dirs': [
-      '..',
-    ],
-    'dependencies': [
-      '<(DEPTH)/base/base.gyp:base',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
-      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
-      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_system',
-    ],
-    'export_dependent_settings': [
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-    ],
-  }, {
-    'target_name': 'mojo_runner_host_lib',
-    'type': 'static_library',
-    'sources': [
-      '../services/shell/runner/host/child_process.cc',
-      '../services/shell/runner/host/child_process.h',
-      '../services/shell/runner/host/child_process_base.cc',
-      '../services/shell/runner/host/child_process_base.h',
-      '../services/shell/runner/host/child_process_host.cc',
-      '../services/shell/runner/host/child_process_host.h',
-      '../services/shell/runner/host/in_process_native_runner.cc',
-      '../services/shell/runner/host/in_process_native_runner.h',
-      '../services/shell/runner/host/out_of_process_native_runner.cc',
-      '../services/shell/runner/host/out_of_process_native_runner.h',
-      '../services/shell/runner/host/native_application_support.cc',
-      '../services/shell/runner/host/native_application_support.h',
-      '../services/shell/runner/init.cc',
-      '../services/shell/runner/init.h',
-    ],
-    'dependencies': [
-      'mojo_runner_common_lib',
-      'mojo_shell_lib',
-      '<(DEPTH)/base/base.gyp:base',
-      '<(DEPTH)/base/base.gyp:base_i18n',
-      '<(DEPTH)/base/base.gyp:base_static',
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
-      '<(DEPTH)/mojo/mojo_platform_handle.gyp:platform_handle',
-      '<(DEPTH)/mojo/mojo_public.gyp:mojo_message_pump_lib',
-    ],
-    'export_dependent_settings': [
-      '<(DEPTH)/mojo/mojo_base.gyp:mojo_application_bindings',
-    ],
-    'conditions': [
-      ['OS=="linux"', {
-        'sources': [
-          '../services/shell/runner/host/linux_sandbox.cc',
-          '../services/shell/runner/host/linux_sandbox.h',
-        ],
-        'dependencies': [
-          '<(DEPTH)/sandbox/sandbox.gyp:sandbox',
-          '<(DEPTH)/sandbox/sandbox.gyp:sandbox_services',
-          '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf',
-          '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf_helpers',
-        ],
-      }],
-      ['OS=="mac"', {
-        'sources': [
-          '../services/shell/runner/host/mach_broker.cc',
-          '../services/shell/runner/host/mach_broker.h',
-        ],
-      }],
-    ],
-  }, {
-    # GN version: //mojo/services/catalog:manifest
-    'target_name': 'mojo_catalog_manifest',
-    'type': 'none',
-    'variables': {
-      'application_type': 'mojo',
-      'application_name': 'catalog',
-      'source_manifest': '<(DEPTH)/mojo/services/catalog/manifest.json',
-    },
-    'includes': [
-      '../mojo/public/mojo_application_manifest.gypi',
-    ],
-    'hard_dependency': 1,
-  }],
-}
diff --git a/mojo/services/BUILD.gn b/mojo/services/BUILD.gn
deleted file mode 100644
index aaf9aab..0000000
--- a/mojo/services/BUILD.gn
+++ /dev/null
@@ -1,14 +0,0 @@
-# Copyright 2014 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//build/config/ui.gni")
-
-group("services") {
-  # Meta-target, don't link into production code.
-  testonly = true
-  deps = [
-    "//mojo/services/catalog",
-    "//mojo/services/tracing",
-  ]
-}
diff --git a/mojo/services/DEPS b/mojo/services/DEPS
deleted file mode 100644
index 594ae4b6..0000000
--- a/mojo/services/DEPS
+++ /dev/null
@@ -1,6 +0,0 @@
-include_rules = [
-  "-mojo",
-  "+mojo/common",
-  "+mojo/public",
-  "+services/shell/public",
-]
diff --git a/mojo/services/public/build/config/BUILD.gn b/mojo/services/public/build/config/BUILD.gn
deleted file mode 100644
index c6b13b6d..0000000
--- a/mojo/services/public/build/config/BUILD.gn
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright 2015 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-# The absolute path to the directory containing the Mojo services produced
-# out of Chromium.
-mojo_services_root = get_path_info("../../..", "abspath")
-
-# NOTE: This config name must be in sync with the name of the config used by
-# services that developed out of the Mojo repo so that Chromium's services'
-# BUILD.gn files can work seamlessly in Chromium and when pulled into Mojo or a
-# client repo.
-config("mojo_services") {
-  include_dirs = [
-    # Include paths in Chromium Mojo services' client-side code are specified
-    # relative to the directory holding the services' client-side code.
-    mojo_services_root,
-
-    # The same goes for files generated from mojoms.
-    root_gen_dir + mojo_services_root,
-  ]
-}
diff --git a/pdf/pdfium/pdfium_engine.cc b/pdf/pdfium/pdfium_engine.cc
index 0005adf..09d8a2f 100644
--- a/pdf/pdfium/pdfium_engine.cc
+++ b/pdf/pdfium/pdfium_engine.cc
@@ -3185,8 +3185,8 @@
           gfx_content_rect, src_page_width, src_page_height, rotated) : 1.0;
 
   // Calculate positions for the clip box.
-  printing::ClipBox media_box;
-  printing::ClipBox crop_box;
+  printing::PdfRectangle media_box;
+  printing::PdfRectangle crop_box;
   bool has_media_box = !!FPDFPage_GetMediaBox(page,
                                               &media_box.left,
                                               &media_box.bottom,
@@ -3199,9 +3199,9 @@
                                             &crop_box.top);
   printing::CalculateMediaBoxAndCropBox(
       rotated, has_media_box, has_crop_box, &media_box, &crop_box);
-  printing::ClipBox source_clip_box =
+  printing::PdfRectangle source_clip_box =
       printing::CalculateClipBoxBoundary(media_box, crop_box);
-  printing::ScaleClipBox(scale_factor, &source_clip_box);
+  printing::ScalePdfRectangle(scale_factor, &source_clip_box);
 
   // Calculate the translation offset values.
   double offset_x = 0;
diff --git a/printing/pdf_transform.cc b/printing/pdf_transform.cc
index f691168..7555bd6 100644
--- a/printing/pdf_transform.cc
+++ b/printing/pdf_transform.cc
@@ -13,13 +13,13 @@
 
 namespace {
 
-// When a ClipBox has top < bottom, or right < left, the values should be
+// When a PdfRectangle has top < bottom, or right < left, the values should be
 // swapped.
-void SwapClipBoxValuesIfNeeded(ClipBox* clip_box) {
-  if (clip_box->top < clip_box->bottom)
-    std::swap(clip_box->top, clip_box->bottom);
-  if (clip_box->right < clip_box->left)
-    std::swap(clip_box->right, clip_box->left);
+void SwapPdfRectangleValuesIfNeeded(PdfRectangle* rect) {
+  if (rect->top < rect->bottom)
+    std::swap(rect->top, rect->bottom);
+  if (rect->right < rect->left)
+    std::swap(rect->right, rect->left);
 }
 
 }  // namespace
@@ -40,7 +40,7 @@
   return std::min(ratio_x, ratio_y);
 }
 
-void SetDefaultClipBox(bool rotated, ClipBox* clip_box) {
+void SetDefaultClipBox(bool rotated, PdfRectangle* clip_box) {
   const int kDpi = 72;
   const float kPaperWidth = 8.5 * kDpi;
   const float kPaperHeight = 11 * kDpi;
@@ -53,12 +53,12 @@
 void CalculateMediaBoxAndCropBox(bool rotated,
                                  bool has_media_box,
                                  bool has_crop_box,
-                                 printing::ClipBox* media_box,
-                                 printing::ClipBox* crop_box) {
+                                 PdfRectangle* media_box,
+                                 PdfRectangle* crop_box) {
   if (has_media_box)
-    SwapClipBoxValuesIfNeeded(media_box);
+    SwapPdfRectangleValuesIfNeeded(media_box);
   if (has_crop_box)
-    SwapClipBoxValuesIfNeeded(crop_box);
+    SwapPdfRectangleValuesIfNeeded(crop_box);
 
   if (!has_media_box && !has_crop_box) {
     SetDefaultClipBox(rotated, crop_box);
@@ -70,28 +70,28 @@
   }
 }
 
-ClipBox CalculateClipBoxBoundary(const ClipBox& media_box,
-                                 const ClipBox& crop_box) {
-  ClipBox clip_box;
+PdfRectangle CalculateClipBoxBoundary(const PdfRectangle& media_box,
+                                      const PdfRectangle& crop_box) {
+  PdfRectangle clip_box;
 
   // Clip |media_box| to the size of |crop_box|, but ignore |crop_box| if it is
   // bigger than |media_box|.
   clip_box.left = std::max(crop_box.left, media_box.left);
+  clip_box.bottom = std::max(crop_box.bottom, media_box.bottom);
   clip_box.right = std::min(crop_box.right, media_box.right);
   clip_box.top = std::min(crop_box.top, media_box.top);
-  clip_box.bottom = std::max(crop_box.bottom, media_box.bottom);
   return clip_box;
 }
 
-void ScaleClipBox(double scale_factor, ClipBox* box) {
-  box->left *= scale_factor;
-  box->right *= scale_factor;
-  box->bottom *= scale_factor;
-  box->top *= scale_factor;
+void ScalePdfRectangle(double scale_factor, PdfRectangle* rect) {
+  rect->left *= scale_factor;
+  rect->bottom *= scale_factor;
+  rect->right *= scale_factor;
+  rect->top *= scale_factor;
 }
 
 void CalculateScaledClipBoxOffset(const gfx::Rect& content_rect,
-                                  const ClipBox& source_clip_box,
+                                  const PdfRectangle& source_clip_box,
                                   double* offset_x,
                                   double* offset_y) {
   const float clip_box_width = source_clip_box.right - source_clip_box.left;
@@ -108,7 +108,7 @@
                                      int rotation,
                                      int page_width,
                                      int page_height,
-                                     const ClipBox& source_clip_box,
+                                     const PdfRectangle& source_clip_box,
                                      double* offset_x,
                                      double* offset_y) {
   // Align the intended clip region to left-top corner of real clip region.
diff --git a/printing/pdf_transform.h b/printing/pdf_transform.h
index 2cc244b..7910f0f 100644
--- a/printing/pdf_transform.h
+++ b/printing/pdf_transform.h
@@ -15,11 +15,11 @@
 
 // A rect struct for use with FPDF bounding box functions.
 // With PDFs, origin is bottom-left.
-struct PRINTING_EXPORT ClipBox {
+struct PRINTING_EXPORT PdfRectangle {
   float left;
+  float bottom;
   float right;
   float top;
-  float bottom;
 };
 
 // Calculate the scale factor between |content_rect| and a page of size
@@ -38,7 +38,7 @@
 // Make the default size to be letter size (8.5" X 11"). We are just following
 // the PDFium way of handling these corner cases. PDFium always consider
 // US-Letter as the default page size.
-PRINTING_EXPORT void SetDefaultClipBox(bool rotated, ClipBox* clip_box);
+PRINTING_EXPORT void SetDefaultClipBox(bool rotated, PdfRectangle* clip_box);
 
 // Set the media box and/or crop box as needed. If both boxes are there, then
 // nothing needs to be done. If one box is missing, then fill it with the value
@@ -47,8 +47,8 @@
 PRINTING_EXPORT void CalculateMediaBoxAndCropBox(bool rotated,
                                                  bool has_media_box,
                                                  bool has_crop_box,
-                                                 printing::ClipBox* media_box,
-                                                 printing::ClipBox* crop_box);
+                                                 PdfRectangle* media_box,
+                                                 PdfRectangle* crop_box);
 
 // Compute source clip box boundaries based on the crop box / media box of
 // source page and scale factor.
@@ -56,11 +56,12 @@
 //
 // |media_box| The PDF's media box.
 // |crop_box| The PDF's crop box.
-PRINTING_EXPORT ClipBox CalculateClipBoxBoundary(const ClipBox& media_box,
-                                                 const ClipBox& crop_box);
+PRINTING_EXPORT PdfRectangle CalculateClipBoxBoundary(
+    const PdfRectangle& media_box,
+    const PdfRectangle& crop_box);
 
 // Scale |box| by |scale_factor|.
-PRINTING_EXPORT void ScaleClipBox(double scale_factor, ClipBox* box);
+PRINTING_EXPORT void ScalePdfRectangle(double scale_factor, PdfRectangle* rect);
 
 // Calculate the clip box translation offset for a page that does need to be
 // scaled. All parameters are in points.
@@ -73,7 +74,7 @@
 // source clip box, relative to origin at left-bottom.
 PRINTING_EXPORT void CalculateScaledClipBoxOffset(
     const gfx::Rect& content_rect,
-    const ClipBox& source_clip_box,
+    const PdfRectangle& source_clip_box,
     double* offset_x,
     double* offset_y);
 
@@ -95,7 +96,7 @@
     int rotation,
     int page_width,
     int page_height,
-    const ClipBox& source_clip_box,
+    const PdfRectangle& source_clip_box,
     double* offset_x,
     double* offset_y);
 
diff --git a/printing/pdf_transform_unittest.cc b/printing/pdf_transform_unittest.cc
index e026ac4..4ee2145 100644
--- a/printing/pdf_transform_unittest.cc
+++ b/printing/pdf_transform_unittest.cc
@@ -17,43 +17,44 @@
 const float kDefaultRatio = kDefaultWidth / kDefaultHeight;
 const double kTolerance = 0.0001;
 
-void ExpectDefaultPortraitBox(const ClipBox& box) {
+void ExpectDefaultPortraitBox(const PdfRectangle& box) {
   EXPECT_FLOAT_EQ(0, box.left);
+  EXPECT_FLOAT_EQ(0, box.bottom);
   EXPECT_FLOAT_EQ(kDefaultWidth, box.right);
   EXPECT_FLOAT_EQ(kDefaultHeight, box.top);
-  EXPECT_FLOAT_EQ(0, box.bottom);
 }
 
-void ExpectDefaultLandscapeBox(const ClipBox& box) {
+void ExpectDefaultLandscapeBox(const PdfRectangle& box) {
   EXPECT_FLOAT_EQ(0, box.left);
+  EXPECT_FLOAT_EQ(0, box.bottom);
   EXPECT_FLOAT_EQ(kDefaultHeight, box.right);
   EXPECT_FLOAT_EQ(kDefaultWidth, box.top);
-  EXPECT_FLOAT_EQ(0, box.bottom);
 }
 
-void ExpectBoxesAreEqual(const ClipBox& expected, const ClipBox& actual) {
+void ExpectBoxesAreEqual(const PdfRectangle& expected,
+                         const PdfRectangle& actual) {
   EXPECT_FLOAT_EQ(expected.left, actual.left);
+  EXPECT_FLOAT_EQ(expected.bottom, actual.bottom);
   EXPECT_FLOAT_EQ(expected.right, actual.right);
   EXPECT_FLOAT_EQ(expected.top, actual.top);
-  EXPECT_FLOAT_EQ(expected.bottom, actual.bottom);
 }
 
-void InitializeBoxToInvalidValues(ClipBox* box) {
-  box->left = box->right = box->top = box->bottom = -1;
+void InitializeBoxToInvalidValues(PdfRectangle* box) {
+  box->left = box->bottom = box->right = box->top = -1;
 }
 
-void InitializeBoxToDefaultPortraitValues(ClipBox* box) {
+void InitializeBoxToDefaultPortraitValues(PdfRectangle* box) {
   box->left = 0;
+  box->bottom = 0;
   box->right = kDefaultWidth;
   box->top = kDefaultHeight;
-  box->bottom = 0;
 }
 
-void InitializeBoxToDefaultLandscapeValue(ClipBox* box) {
+void InitializeBoxToDefaultLandscapeValue(PdfRectangle* box) {
   box->left = 0;
+  box->bottom = 0;
   box->right = kDefaultHeight;
   box->top = kDefaultWidth;
-  box->bottom = 0;
 }
 
 }  // namespace
@@ -98,7 +99,7 @@
 }
 
 TEST(PdfTransformTest, SetDefaultClipBox) {
-  ClipBox box;
+  PdfRectangle box;
 
   SetDefaultClipBox(false, &box);
   ExpectDefaultPortraitBox(box);
@@ -108,8 +109,8 @@
 }
 
 TEST(PdfTransformTest, CalculateMediaBoxAndCropBox) {
-  ClipBox media_box;
-  ClipBox crop_box;
+  PdfRectangle media_box;
+  PdfRectangle crop_box;
 
   // Assume both boxes are there.
   InitializeBoxToDefaultPortraitValues(&media_box);
@@ -129,11 +130,7 @@
   ExpectDefaultLandscapeBox(crop_box);
 
   // Assume crop box is missing.
-  ClipBox expected_box;
-  expected_box.left = 0;
-  expected_box.right = 42;
-  expected_box.top = 420;
-  expected_box.bottom = 0;
+  const PdfRectangle expected_box = {0, 0, 42, 420};
   media_box = expected_box;
   InitializeBoxToInvalidValues(&crop_box);
   CalculateMediaBoxAndCropBox(false, true, false, &media_box, &crop_box);
@@ -148,9 +145,9 @@
 }
 
 TEST(PdfTransformTest, CalculateClipBoxBoundary) {
-  ClipBox media_box;
-  ClipBox crop_box;
-  ClipBox result;
+  PdfRectangle media_box;
+  PdfRectangle crop_box;
+  PdfRectangle result;
 
   // media box and crop box are the same.
   InitializeBoxToDefaultPortraitValues(&media_box);
@@ -162,37 +159,37 @@
   InitializeBoxToDefaultLandscapeValue(&crop_box);
   result = CalculateClipBoxBoundary(media_box, crop_box);
   EXPECT_FLOAT_EQ(0, result.left);
+  EXPECT_FLOAT_EQ(0, result.bottom);
   EXPECT_FLOAT_EQ(kDefaultWidth, result.right);
   EXPECT_FLOAT_EQ(kDefaultWidth, result.top);
-  EXPECT_FLOAT_EQ(0, result.bottom);
 
   // crop box is smaller than media box.
   crop_box.left = 0;
-  crop_box.right = 100;
   crop_box.bottom = 0;
+  crop_box.right = 100;
   crop_box.top = 200;
   result = CalculateClipBoxBoundary(media_box, crop_box);
   EXPECT_FLOAT_EQ(0, result.left);
+  EXPECT_FLOAT_EQ(0, result.bottom);
   EXPECT_FLOAT_EQ(100, result.right);
   EXPECT_FLOAT_EQ(200, result.top);
-  EXPECT_FLOAT_EQ(0, result.bottom);
 
   // crop box is smaller than the media box in one dimension and longer in the
   // other.
   crop_box.left = 0;
-  crop_box.right = 100;
   crop_box.bottom = 0;
+  crop_box.right = 100;
   crop_box.top = 2000;
   result = CalculateClipBoxBoundary(media_box, crop_box);
   EXPECT_FLOAT_EQ(0, result.left);
+  EXPECT_FLOAT_EQ(0, result.bottom);
   EXPECT_FLOAT_EQ(100, result.right);
   EXPECT_FLOAT_EQ(kDefaultHeight, result.top);
-  EXPECT_FLOAT_EQ(0, result.bottom);
 }
 
 TEST(PdfTransformTest, CalculateScaledClipBoxOffset) {
   const gfx::Rect rect(kDefaultWidth, kDefaultHeight);
-  ClipBox clip_box;
+  PdfRectangle clip_box;
   double offset_x;
   double offset_y;
 
@@ -214,7 +211,7 @@
   int page_width = kDefaultWidth;
   int page_height = kDefaultHeight;
   const gfx::Rect rect(kDefaultWidth, kDefaultHeight);
-  ClipBox clip_box;
+  PdfRectangle clip_box;
   double offset_x;
   double offset_y;
 
@@ -284,12 +281,12 @@
   int page_width = kDefaultWidth;
   int page_height = kDefaultHeight;
   const gfx::Rect rect(kDefaultWidth, kDefaultHeight);
-  ClipBox clip_box;
+  PdfRectangle clip_box;
   double offset_x;
   double offset_y;
 
-  const ClipBox expected_media_box_b491160 = {0, 612, 0, -792};
-  ClipBox media_box_b491160 = {0, 612, -792, 0};
+  const PdfRectangle expected_media_box_b491160 = {0, -792, 612, 0};
+  PdfRectangle media_box_b491160 = {0, 0, 612, -792};
   CalculateMediaBoxAndCropBox(false, true, false, &media_box_b491160,
                               &clip_box);
   ExpectBoxesAreEqual(expected_media_box_b491160, media_box_b491160);
@@ -304,7 +301,7 @@
   EXPECT_DOUBLE_EQ(0, offset_x);
   EXPECT_DOUBLE_EQ(792, offset_y);
 
-  ClipBox media_box_b588757 = {0, 612, 0, 792};
+  PdfRectangle media_box_b588757 = {0, 792, 612, 0};
   CalculateMediaBoxAndCropBox(false, true, false, &media_box_b588757,
                               &clip_box);
   ExpectDefaultPortraitBox(media_box_b588757);
@@ -319,7 +316,7 @@
   EXPECT_DOUBLE_EQ(0, offset_x);
   EXPECT_DOUBLE_EQ(0, offset_y);
 
-  ClipBox media_box_left_right_flipped = {612, 0, 0, 792};
+  PdfRectangle media_box_left_right_flipped = {612, 792, 0, 0};
   CalculateMediaBoxAndCropBox(false, true, false, &media_box_left_right_flipped,
                               &clip_box);
   ExpectDefaultPortraitBox(media_box_left_right_flipped);
diff --git a/mojo/services/catalog/BUILD.gn b/services/catalog/BUILD.gn
similarity index 95%
rename from mojo/services/catalog/BUILD.gn
rename to services/catalog/BUILD.gn
index a9f5eaa..f491aa9 100644
--- a/mojo/services/catalog/BUILD.gn
+++ b/services/catalog/BUILD.gn
@@ -30,8 +30,8 @@
   deps = [
     "//base",
     "//mojo/common:url_type_converters",
-    "//mojo/services/catalog/public/interfaces",
     "//mojo/util:filename_util",
+    "//services/catalog/public/interfaces",
     "//services/shell/public/cpp",
   ]
 
diff --git a/mojo/services/catalog/DEPS b/services/catalog/DEPS
similarity index 63%
rename from mojo/services/catalog/DEPS
rename to services/catalog/DEPS
index f089a42a..a40f31c 100644
--- a/mojo/services/catalog/DEPS
+++ b/services/catalog/DEPS
@@ -1,6 +1,5 @@
 include_rules = [
   "+base",
-  "+mojo/common",
+  "+mojo",
   "+services/shell/public",
-  "+mojo/util",
 ]
diff --git a/mojo/services/catalog/catalog.cc b/services/catalog/catalog.cc
similarity index 97%
rename from mojo/services/catalog/catalog.cc
rename to services/catalog/catalog.cc
index dd679f9..3a45f77 100644
--- a/mojo/services/catalog/catalog.cc
+++ b/services/catalog/catalog.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 "mojo/services/catalog/catalog.h"
+#include "services/catalog/catalog.h"
 
 #include "base/bind.h"
 #include "base/json/json_file_value_serializer.h"
@@ -11,9 +11,9 @@
 #include "base/task_runner_util.h"
 #include "base/thread_task_runner_handle.h"
 #include "mojo/common/url_type_converters.h"
-#include "mojo/services/catalog/entry.h"
-#include "mojo/services/catalog/manifest_provider.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/entry.h"
+#include "services/catalog/manifest_provider.h"
+#include "services/catalog/store.h"
 #include "services/shell/public/cpp/names.h"
 #include "url/gurl.h"
 #include "url/url_util.h"
diff --git a/mojo/services/catalog/catalog.h b/services/catalog/catalog.h
similarity index 90%
rename from mojo/services/catalog/catalog.h
rename to services/catalog/catalog.h
index 640ba1a..48cda4c 100644
--- a/mojo/services/catalog/catalog.h
+++ b/services/catalog/catalog.h
@@ -2,19 +2,19 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_SERVICES_CATALOG_CATALOG_H_
-#define MOJO_SERVICES_CATALOG_CATALOG_H_
+#ifndef SERVICES_CATALOG_CATALOG_H_
+#define SERVICES_CATALOG_CATALOG_H_
 
 #include "base/files/file_path.h"
 #include "base/memory/weak_ptr.h"
 #include "base/path_service.h"
 #include "base/values.h"
 #include "mojo/public/cpp/bindings/binding_set.h"
-#include "mojo/services/catalog/entry.h"
-#include "mojo/services/catalog/public/interfaces/catalog.mojom.h"
-#include "mojo/services/catalog/public/interfaces/resolver.mojom.h"
-#include "mojo/services/catalog/store.h"
-#include "mojo/services/catalog/types.h"
+#include "services/catalog/entry.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/interfaces/resolver.mojom.h"
+#include "services/catalog/store.h"
+#include "services/catalog/types.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/interfaces/shell_resolver.mojom.h"
 
@@ -112,4 +112,4 @@
 
 }  // namespace catalog
 
-#endif  // MOJO_SERVICES_CATALOG_CATALOG_H_
+#endif  // SERVICES_CATALOG_CATALOG_H_
diff --git a/mojo/services/catalog/data/capabilities b/services/catalog/data/capabilities
similarity index 100%
rename from mojo/services/catalog/data/capabilities
rename to services/catalog/data/capabilities
diff --git a/mojo/services/catalog/data/instance b/services/catalog/data/instance
similarity index 100%
rename from mojo/services/catalog/data/instance
rename to services/catalog/data/instance
diff --git a/mojo/services/catalog/data/malformed b/services/catalog/data/malformed
similarity index 100%
rename from mojo/services/catalog/data/malformed
rename to services/catalog/data/malformed
diff --git a/mojo/services/catalog/data/serialization b/services/catalog/data/serialization
similarity index 100%
rename from mojo/services/catalog/data/serialization
rename to services/catalog/data/serialization
diff --git a/mojo/services/catalog/data/simple b/services/catalog/data/simple
similarity index 100%
rename from mojo/services/catalog/data/simple
rename to services/catalog/data/simple
diff --git a/mojo/services/catalog/entry.cc b/services/catalog/entry.cc
similarity index 98%
rename from mojo/services/catalog/entry.cc
rename to services/catalog/entry.cc
index c806822..8d0784ba 100644
--- a/mojo/services/catalog/entry.cc
+++ b/services/catalog/entry.cc
@@ -2,11 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/services/catalog/entry.h"
+#include "services/catalog/entry.h"
 
 #include "base/values.h"
-#include "mojo/services/catalog/store.h"
 #include "mojo/util/filename_util.h"
+#include "services/catalog/store.h"
 #include "services/shell/public/cpp/names.h"
 #include "url/gurl.h"
 
diff --git a/mojo/services/catalog/entry.h b/services/catalog/entry.h
similarity index 94%
rename from mojo/services/catalog/entry.h
rename to services/catalog/entry.h
index af3df4c..48ad1fb 100644
--- a/mojo/services/catalog/entry.h
+++ b/services/catalog/entry.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 MOJO_SERVICES_CATALOG_ENTRY_H_
-#define MOJO_SERVICES_CATALOG_ENTRY_H_
+#ifndef SERVICES_CATALOG_ENTRY_H_
+#define SERVICES_CATALOG_ENTRY_H_
 
 #include <set>
 #include <string>
@@ -73,4 +73,4 @@
 };
 }
 
-#endif  // MOJO_SERVICES_CATALOG_ENTRY_H_
+#endif  // SERVICES_CATALOG_ENTRY_H_
diff --git a/mojo/services/catalog/entry_unittest.cc b/services/catalog/entry_unittest.cc
similarity index 96%
rename from mojo/services/catalog/entry_unittest.cc
rename to services/catalog/entry_unittest.cc
index 643841c..47e286d 100644
--- a/mojo/services/catalog/entry_unittest.cc
+++ b/services/catalog/entry_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 "mojo/services/catalog/entry.h"
+#include "services/catalog/entry.h"
 
 #include "base/files/file_path.h"
 #include "base/json/json_file_value_serializer.h"
@@ -35,7 +35,7 @@
     base::FilePath manifest_path;
     PathService::Get(base::DIR_SOURCE_ROOT, &manifest_path);
     manifest_path = manifest_path.AppendASCII(
-        "mojo/services/catalog/data/" + manifest);
+        "services/catalog/data/" + manifest);
 
     JSONFileValueDeserializer deserializer(manifest_path);
     int error = 0;
diff --git a/mojo/services/catalog/factory.cc b/services/catalog/factory.cc
similarity index 96%
rename from mojo/services/catalog/factory.cc
rename to services/catalog/factory.cc
index bef55df..d687b887 100644
--- a/mojo/services/catalog/factory.cc
+++ b/services/catalog/factory.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/services/catalog/factory.h"
+#include "services/catalog/factory.h"
 
 #include "base/bind.h"
-#include "mojo/services/catalog/catalog.h"
+#include "services/catalog/catalog.h"
 #include "services/shell/public/cpp/connection.h"
 #include "services/shell/public/cpp/shell_connection.h"
 
diff --git a/mojo/services/catalog/factory.h b/services/catalog/factory.h
similarity index 88%
rename from mojo/services/catalog/factory.h
rename to services/catalog/factory.h
index df7d369..70f9221a 100644
--- a/mojo/services/catalog/factory.h
+++ b/services/catalog/factory.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 MOJO_SERVICES_CATALOG_FACTORY_H_
-#define MOJO_SERVICES_CATALOG_FACTORY_H_
+#ifndef SERVICES_CATALOG_FACTORY_H_
+#define SERVICES_CATALOG_FACTORY_H_
 
 #include <map>
 #include <string>
@@ -12,9 +12,9 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "mojo/services/catalog/public/interfaces/catalog.mojom.h"
-#include "mojo/services/catalog/public/interfaces/resolver.mojom.h"
-#include "mojo/services/catalog/types.h"
+#include "services/catalog/public/interfaces/catalog.mojom.h"
+#include "services/catalog/public/interfaces/resolver.mojom.h"
+#include "services/catalog/types.h"
 #include "services/shell/public/cpp/shell_client.h"
 #include "services/shell/public/interfaces/shell_client.mojom.h"
 #include "services/shell/public/interfaces/shell_resolver.mojom.h"
@@ -85,4 +85,4 @@
 
 }  // namespace catalog
 
-#endif  // MOJO_SERVICES_CATALOG_FACTORY_H_
+#endif  // SERVICES_CATALOG_FACTORY_H_
diff --git a/mojo/services/catalog/manifest.json b/services/catalog/manifest.json
similarity index 100%
rename from mojo/services/catalog/manifest.json
rename to services/catalog/manifest.json
diff --git a/mojo/services/catalog/manifest_provider.h b/services/catalog/manifest_provider.h
similarity index 83%
rename from mojo/services/catalog/manifest_provider.h
rename to services/catalog/manifest_provider.h
index f3cf101..7a64e49d 100644
--- a/mojo/services/catalog/manifest_provider.h
+++ b/services/catalog/manifest_provider.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 MOJO_SERVICES_CATALOG_MANIFEST_PROVIDER_H_
-#define MOJO_SERVICES_CATALOG_MANIFEST_PROVIDER_H_
+#ifndef SERVICES_CATALOG_MANIFEST_PROVIDER_H_
+#define SERVICES_CATALOG_MANIFEST_PROVIDER_H_
 
 #include <string>
 
@@ -26,4 +26,4 @@
 
 }  // namespace catalog
 
-#endif  // MOJO_SERVICES_CATALOG_MANIFEST_PROVIDER_H_
+#endif  // SERVICES_CATALOG_MANIFEST_PROVIDER_H_
diff --git a/mojo/services/catalog/public/interfaces/BUILD.gn b/services/catalog/public/interfaces/BUILD.gn
similarity index 75%
rename from mojo/services/catalog/public/interfaces/BUILD.gn
rename to services/catalog/public/interfaces/BUILD.gn
index 299b7dd..1c0d6af6 100644
--- a/mojo/services/catalog/public/interfaces/BUILD.gn
+++ b/services/catalog/public/interfaces/BUILD.gn
@@ -9,10 +9,4 @@
     "catalog.mojom",
     "resolver.mojom",
   ]
-
-  import_dirs = [ "//mojo/services" ]
-
-  deps = [
-    "//services/shell/public/interfaces",
-  ]
 }
diff --git a/mojo/services/catalog/public/interfaces/catalog.mojom b/services/catalog/public/interfaces/catalog.mojom
similarity index 100%
rename from mojo/services/catalog/public/interfaces/catalog.mojom
rename to services/catalog/public/interfaces/catalog.mojom
diff --git a/mojo/services/catalog/public/interfaces/resolver.mojom b/services/catalog/public/interfaces/resolver.mojom
similarity index 100%
rename from mojo/services/catalog/public/interfaces/resolver.mojom
rename to services/catalog/public/interfaces/resolver.mojom
diff --git a/mojo/services/catalog/store.cc b/services/catalog/store.cc
similarity index 95%
rename from mojo/services/catalog/store.cc
rename to services/catalog/store.cc
index 6c1a6d6..9d1cd452 100644
--- a/mojo/services/catalog/store.cc
+++ b/services/catalog/store.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 "mojo/services/catalog/store.h"
+#include "services/catalog/store.h"
 
 namespace catalog {
 
diff --git a/mojo/services/catalog/store.h b/services/catalog/store.h
similarity index 93%
rename from mojo/services/catalog/store.h
rename to services/catalog/store.h
index 4ebdaea..a57e154d 100644
--- a/mojo/services/catalog/store.h
+++ b/services/catalog/store.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 MOJO_SERVICES_CATALOG_STORE_H_
-#define MOJO_SERVICES_CATALOG_STORE_H_
+#ifndef SERVICES_CATALOG_STORE_H_
+#define SERVICES_CATALOG_STORE_H_
 
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
@@ -51,4 +51,4 @@
 
 }  // namespace catalog
 
-#endif  // MOJO_SERVICES_CATALOG_STORE_H_
+#endif  // SERVICES_CATALOG_STORE_H_
diff --git a/mojo/services/catalog/types.h b/services/catalog/types.h
similarity index 77%
rename from mojo/services/catalog/types.h
rename to services/catalog/types.h
index 1be44d5..1c66890 100644
--- a/mojo/services/catalog/types.h
+++ b/services/catalog/types.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 MOJO_SERVICES_CATALOG_TYPES_H_
-#define MOJO_SERVICES_CATALOG_TYPES_H_
+#ifndef SERVICES_CATALOG_TYPES_H_
+#define SERVICES_CATALOG_TYPES_H_
 
 #include <map>
 #include <string>
@@ -19,4 +19,4 @@
 
 }  // namespace catalog
 
-#endif  // MOJO_SERVICES_CATALOG_TYPES_H_
+#endif  // SERVICES_CATALOG_TYPES_H_
diff --git a/services/shell/BUILD.gn b/services/shell/BUILD.gn
index d815734..e3ce5fa 100644
--- a/services/shell/BUILD.gn
+++ b/services/shell/BUILD.gn
@@ -38,8 +38,8 @@
     "//base/third_party/dynamic_annotations",
     "//mojo/common",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/catalog/public/interfaces",
     "//mojo/util:filename_util",
+    "//services/catalog/public/interfaces",
     "//services/shell/public/cpp:sources",
     "//services/shell/public/interfaces",
     "//url",
@@ -47,7 +47,7 @@
 
   public_deps = [
     # ApplicationManager exposes and uses PackageManager types in its header.
-    "//mojo/services/catalog:lib",
+    "//services/catalog:lib",
   ]
 
   data_deps = [
@@ -55,7 +55,7 @@
   ]
 
   # For services/shell/loader.h
-  allow_circular_includes_from = [ "//mojo/services/catalog:lib" ]
+  allow_circular_includes_from = [ "//services/catalog:lib" ]
 }
 
 mojo_application_manifest("manifest") {
diff --git a/services/shell/background/BUILD.gn b/services/shell/background/BUILD.gn
index b931cd8..31821aa 100644
--- a/services/shell/background/BUILD.gn
+++ b/services/shell/background/BUILD.gn
@@ -18,7 +18,7 @@
   deps = [
     "//base",
     "//mojo/message_pump",
-    "//mojo/services/catalog:lib",
+    "//services/catalog:lib",
     "//services/shell",
     "//services/shell/public/cpp:sources",
     "//services/shell/runner:init",
diff --git a/services/shell/background/DEPS b/services/shell/background/DEPS
index 175fafb..3fd6080b 100644
--- a/services/shell/background/DEPS
+++ b/services/shell/background/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+mojo/services/catalog",
+  "+services/catalog",
 ]
diff --git a/services/shell/background/background_shell.cc b/services/shell/background/background_shell.cc
index b4a6163b..629f58c7 100644
--- a/services/shell/background/background_shell.cc
+++ b/services/shell/background/background_shell.cc
@@ -12,7 +12,7 @@
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/simple_thread.h"
 #include "mojo/message_pump/message_pump_mojo.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/store.h"
 #include "services/shell/connect_params.h"
 #include "services/shell/loader.h"
 #include "services/shell/public/cpp/shell_client.h"
diff --git a/services/shell/background/background_shell.h b/services/shell/background/background_shell.h
index b3bc2cf..f61ab5b7 100644
--- a/services/shell/background/background_shell.h
+++ b/services/shell/background/background_shell.h
@@ -10,7 +10,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_ptr.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/store.h"
 #include "services/shell/public/interfaces/shell_client.mojom.h"
 
 namespace catalog {
diff --git a/services/shell/background/tests/BUILD.gn b/services/shell/background/tests/BUILD.gn
index 674b29d..eaf84694 100644
--- a/services/shell/background/tests/BUILD.gn
+++ b/services/shell/background/tests/BUILD.gn
@@ -14,7 +14,7 @@
 
   deps = [
     "//base",
-    "//mojo/services/catalog:lib",
+    "//services/catalog:lib",
     "//url",
   ]
 }
diff --git a/services/shell/background/tests/test_catalog_store.h b/services/shell/background/tests/test_catalog_store.h
index e0145f43..763fdc4e 100644
--- a/services/shell/background/tests/test_catalog_store.h
+++ b/services/shell/background/tests/test_catalog_store.h
@@ -9,7 +9,7 @@
 
 #include "base/memory/scoped_ptr.h"
 #include "base/values.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/store.h"
 
 namespace mojo {
 namespace shell {
diff --git a/services/shell/shell.gyp b/services/shell/shell.gyp
new file mode 100644
index 0000000..6cc23ba
--- /dev/null
+++ b/services/shell/shell.gyp
@@ -0,0 +1,236 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+  'targets': [{
+    'target_name': 'shell_interfaces',
+    'type': 'none',
+    'variables': {
+      'mojom_files': [
+        '../catalog/public/interfaces/catalog.mojom',
+        '../catalog/public/interfaces/resolver.mojom',
+        'public/interfaces/capabilities.mojom',
+        'public/interfaces/connector.mojom',
+        'public/interfaces/interface_provider.mojom',
+        'public/interfaces/shell.mojom',
+        'public/interfaces/shell_client.mojom',
+        'public/interfaces/shell_client_factory.mojom',
+        'public/interfaces/shell_resolver.mojom',
+      ],
+    },
+    'includes': [ '../../mojo/mojom_bindings_generator_explicit.gypi' ],
+  },
+  {
+    # GN version: //services/shell/public/cpp
+    'target_name': 'shell_public',
+    'type': 'static_library',
+    'sources': [
+      'public/cpp/application_runner.h',
+      'public/cpp/capabilities.h',
+      'public/cpp/connect.h',
+      'public/cpp/connection.h',
+      'public/cpp/connector.h',
+      'public/cpp/identity.h',
+      'public/cpp/initialize_base_and_icu.cc',
+      'public/cpp/initialize_base_and_icu.h',
+      'public/cpp/interface_binder.h',
+      'public/cpp/interface_factory.h',
+      'public/cpp/interface_factory_impl.h',
+      'public/cpp/interface_registry.h',
+      'public/cpp/lib/application_runner.cc',
+      'public/cpp/lib/capabilities.cc',
+      'public/cpp/lib/connection_impl.cc',
+      'public/cpp/lib/connection_impl.h',
+      'public/cpp/lib/connector_impl.cc',
+      'public/cpp/lib/connector_impl.h',
+      'public/cpp/lib/identity.cc',
+      'public/cpp/lib/interface_factory_binder.h',
+      'public/cpp/lib/interface_registry.cc',
+      'public/cpp/lib/message_loop_ref.cc',
+      'public/cpp/lib/names.cc',
+      'public/cpp/lib/shell_client.cc',
+      'public/cpp/lib/shell_connection.cc',
+      'public/cpp/message_loop_ref.h',
+      'public/cpp/names.h',
+      'public/cpp/shell.h',
+      'public/cpp/shell_client.h',
+      'public/cpp/shell_connection.h',
+    ],
+    'dependencies': [
+      'shell_interfaces',
+      '<(DEPTH)/base/base.gyp:base_i18n',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_message_pump_lib',
+    ],
+  }, {
+    'target_name': 'shell_lib',
+    'type': 'static_library',
+    'sources': [
+      '../catalog/catalog.cc',
+      '../catalog/catalog.h',
+      '../catalog/entry.cc',
+      '../catalog/entry.h',
+      '../catalog/factory.cc',
+      '../catalog/factory.h',
+      '../catalog/store.cc',
+      '../catalog/store.h',
+      '../catalog/types.h',
+      'loader.h',
+      'connect_params.cc',
+      'connect_params.h',
+      'connect_util.cc',
+      'connect_util.h',
+      'native_runner.h',
+      'native_runner_delegate.h',
+      'shell.cc',
+      'shell.h',
+      'switches.cc',
+      'switches.cc',
+      '<(DEPTH)/mojo/util/filename_util.cc',
+      '<(DEPTH)/mojo/util/filename_util.h',
+    ],
+    'dependencies': [
+      'shell_public',
+      '<(DEPTH)/base/base.gyp:base',
+      '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
+      '<(DEPTH)/net/net.gyp:net',
+      '<(DEPTH)/url/url.gyp:url_lib',
+    ],
+    'export_dependent_settings': [
+      'shell_public',
+    ],
+  }, {
+    'target_name': 'mojo_shell_unittests',
+    'type': 'executable',
+    'sources': [
+      'tests/loader_unittest.cc',
+    ],
+    'dependencies': [
+      'shell_lib',
+      'shell_public',
+      'shell_test_interfaces',
+      '<(DEPTH)/base/base.gyp:base',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_common_lib',
+      '<(DEPTH)/mojo/mojo_base.gyp:mojo_url_type_converters',
+      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_run_all_unittests',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+      '<(DEPTH)/testing/gtest.gyp:gtest',
+      '<(DEPTH)/url/url.gyp:url_lib',
+    ]
+  }, {
+    'target_name': 'shell_test_interfaces',
+    'type': 'static_library',
+    'variables': {
+      'mojom_files': [
+        'tests/test.mojom',
+      ],
+    },
+    'includes': [
+      '../../mojo/mojom_bindings_generator_explicit.gypi',
+    ],
+  }, {
+    'target_name': 'shell_runner_common_lib',
+    'type': 'static_library',
+    'sources': [
+      'runner/common/client_util.cc',
+      'runner/common/client_util.h',
+      'runner/common/switches.cc',
+      'runner/common/switches.h',
+    ],
+    'include_dirs': [
+      '..',
+    ],
+    'dependencies': [
+      'shell_public',
+      '<(DEPTH)/base/base.gyp:base',
+      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_bindings',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_cpp_system',
+    ],
+    'export_dependent_settings': [
+      'shell_public',
+    ],
+  }, {
+    'target_name': 'shell_runner_host_lib',
+    'type': 'static_library',
+    'sources': [
+      'runner/host/child_process.cc',
+      'runner/host/child_process.h',
+      'runner/host/child_process_base.cc',
+      'runner/host/child_process_base.h',
+      'runner/host/child_process_host.cc',
+      'runner/host/child_process_host.h',
+      'runner/host/in_process_native_runner.cc',
+      'runner/host/in_process_native_runner.h',
+      'runner/host/out_of_process_native_runner.cc',
+      'runner/host/out_of_process_native_runner.h',
+      'runner/host/native_application_support.cc',
+      'runner/host/native_application_support.h',
+      'runner/init.cc',
+      'runner/init.h',
+    ],
+    'dependencies': [
+      'shell_lib',
+      'shell_public',
+      'shell_runner_common_lib',
+      '<(DEPTH)/base/base.gyp:base',
+      '<(DEPTH)/base/base.gyp:base_i18n',
+      '<(DEPTH)/base/base.gyp:base_static',
+      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_system_impl',
+      '<(DEPTH)/mojo/mojo_platform_handle.gyp:platform_handle',
+      '<(DEPTH)/mojo/mojo_public.gyp:mojo_message_pump_lib',
+    ],
+    'export_dependent_settings': [
+      'shell_public',
+    ],
+    'conditions': [
+      ['OS=="linux"', {
+        'sources': [
+          'runner/host/linux_sandbox.cc',
+          'runner/host/linux_sandbox.h',
+        ],
+        'dependencies': [
+          '<(DEPTH)/sandbox/sandbox.gyp:sandbox',
+          '<(DEPTH)/sandbox/sandbox.gyp:sandbox_services',
+          '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf',
+          '<(DEPTH)/sandbox/sandbox.gyp:seccomp_bpf_helpers',
+        ],
+      }],
+      ['OS=="mac"', {
+        'sources': [
+          'runner/host/mach_broker.cc',
+          'runner/host/mach_broker.h',
+        ],
+      }],
+    ],
+  }, {
+    # GN version: //services/catalog:manifest
+    'target_name': 'catalog_manifest',
+    'type': 'none',
+    'variables': {
+      'application_type': 'mojo',
+      'application_name': 'catalog',
+      'source_manifest': '<(DEPTH)/services/catalog/manifest.json',
+    },
+    'includes': [
+      '../../mojo/public/mojo_application_manifest.gypi',
+    ],
+    'hard_dependency': 1,
+  }, {
+    # GN version: //services/shell/public/cpp/tests
+    'target_name': 'shell_client_lib_unittests',
+    'type': 'executable',
+    'dependencies': [
+      'shell_public',
+      '<(DEPTH)/base/base.gyp:base',
+      '<(DEPTH)/mojo/mojo_edk.gyp:mojo_run_all_unittests',
+      '<(DEPTH)/testing/gtest.gyp:gtest',
+    ],
+    'sources': [
+      'public/cpp/tests/interface_registry_unittest.cc',
+    ],
+  }],
+}
diff --git a/services/shell/standalone/BUILD.gn b/services/shell/standalone/BUILD.gn
index dc6c7caf..242ee50 100644
--- a/services/shell/standalone/BUILD.gn
+++ b/services/shell/standalone/BUILD.gn
@@ -37,17 +37,17 @@
     "//components/tracing:startup_tracing",
     "//mojo/edk/system",
     "//mojo/message_pump",
-    "//mojo/services/catalog:lib",
-    "//mojo/services/tracing/public/cpp",
-    "//mojo/services/tracing/public/interfaces",
+    "//services/catalog:lib",
     "//services/shell",
     "//services/shell/public/cpp",
     "//services/shell/runner/host:lib",
+    "//services/tracing/public/cpp",
+    "//services/tracing/public/interfaces",
     "//url",
   ]
 
   data_deps = [
-    "//mojo/services/tracing",
+    "//services/tracing",
   ]
 
   # This target includes some files behind #ifdef OS... guards. Since gn is not
diff --git a/services/shell/standalone/DEPS b/services/shell/standalone/DEPS
index b404f56..4af7024 100644
--- a/services/shell/standalone/DEPS
+++ b/services/shell/standalone/DEPS
@@ -1,5 +1,5 @@
 include_rules = [
   "+components/tracing",
-  "+mojo/services/catalog",
-  "+mojo/services/tracing",
+  "+services/catalog",
+  "+services/tracing",
 ]
diff --git a/services/shell/standalone/context.cc b/services/shell/standalone/context.cc
index 3e295dc7..0588726 100644
--- a/services/shell/standalone/context.cc
+++ b/services/shell/standalone/context.cc
@@ -29,19 +29,19 @@
 #include "components/tracing/tracing_switches.h"
 #include "mojo/edk/embedder/embedder.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "mojo/services/catalog/factory.h"
-#include "mojo/services/catalog/store.h"
-#include "mojo/services/tracing/public/cpp/switches.h"
-#include "mojo/services/tracing/public/cpp/trace_provider_impl.h"
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
 #include "mojo/util/filename_util.h"
+#include "services/catalog/factory.h"
+#include "services/catalog/store.h"
 #include "services/shell/connect_params.h"
 #include "services/shell/public/cpp/names.h"
 #include "services/shell/runner/host/in_process_native_runner.h"
 #include "services/shell/runner/host/out_of_process_native_runner.h"
 #include "services/shell/standalone/tracer.h"
 #include "services/shell/switches.h"
+#include "services/tracing/public/cpp/switches.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
 
 #if defined(OS_MACOSX)
 #include "services/shell/runner/host/mach_broker.h"
diff --git a/services/shell/standalone/tracer.h b/services/shell/standalone/tracer.h
index b338272..18e27f5 100644
--- a/services/shell/standalone/tracer.h
+++ b/services/shell/standalone/tracer.h
@@ -14,8 +14,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "mojo/common/data_pipe_drainer.h"
-#include "mojo/services/tracing/public/cpp/trace_provider_impl.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
 
 namespace mojo {
 namespace shell {
diff --git a/services/shell/tests/BUILD.gn b/services/shell/tests/BUILD.gn
index 23e0032..8ffc76d 100644
--- a/services/shell/tests/BUILD.gn
+++ b/services/shell/tests/BUILD.gn
@@ -24,8 +24,8 @@
     "//base/test:test_support",
     "//mojo/public/cpp/bindings",
     "//mojo/public/cpp/system",
-    "//mojo/services/catalog:unittests",
     "//mojo/util:filename_util",
+    "//services/catalog:unittests",
     "//services/shell",
     "//services/shell/background:lib",
     "//services/shell/background:main",
diff --git a/services/shell/tests/DEPS b/services/shell/tests/DEPS
index 175fafb..3fd6080b 100644
--- a/services/shell/tests/DEPS
+++ b/services/shell/tests/DEPS
@@ -1,3 +1,3 @@
 include_rules = [
-  "+mojo/services/catalog",
+  "+services/catalog",
 ]
diff --git a/services/shell/tests/loader_unittest.cc b/services/shell/tests/loader_unittest.cc
index 776163c..f9c5954 100644
--- a/services/shell/tests/loader_unittest.cc
+++ b/services/shell/tests/loader_unittest.cc
@@ -11,8 +11,8 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "mojo/services/catalog/factory.h"
-#include "mojo/services/catalog/store.h"
+#include "services/catalog/factory.h"
+#include "services/catalog/store.h"
 #include "services/shell/connect_util.h"
 #include "services/shell/loader.h"
 #include "services/shell/public/cpp/connector.h"
diff --git a/mojo/services/tracing/BUILD.gn b/services/tracing/BUILD.gn
similarity index 94%
rename from mojo/services/tracing/BUILD.gn
rename to services/tracing/BUILD.gn
index 15df5a5..e63d3700 100644
--- a/mojo/services/tracing/BUILD.gn
+++ b/services/tracing/BUILD.gn
@@ -41,7 +41,7 @@
   deps = [
     "//base",
     "//mojo/common:common_base",
-    "//mojo/services/tracing/public/interfaces",
     "//services/shell/public/cpp",
+    "//services/tracing/public/interfaces",
   ]
 }
diff --git a/mojo/services/tracing/DEPS b/services/tracing/DEPS
similarity index 78%
rename from mojo/services/tracing/DEPS
rename to services/tracing/DEPS
index 8d1f46a..3d22cf3 100644
--- a/mojo/services/tracing/DEPS
+++ b/services/tracing/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
+  "+mojo",
   "+services/shell",
 ]
diff --git a/mojo/services/tracing/main.cc b/services/tracing/main.cc
similarity index 89%
rename from mojo/services/tracing/main.cc
rename to services/tracing/main.cc
index d56d583..9142263 100644
--- a/mojo/services/tracing/main.cc
+++ b/services/tracing/main.cc
@@ -3,8 +3,8 @@
 // found in the LICENSE file.
 
 #include "mojo/public/c/system/main.h"
-#include "mojo/services/tracing/tracing_app.h"
 #include "services/shell/public/cpp/application_runner.h"
+#include "services/tracing/tracing_app.h"
 
 MojoResult MojoMain(MojoHandle shell_handle) {
   mojo::ApplicationRunner runner(new tracing::TracingApp);
diff --git a/mojo/services/tracing/manifest.json b/services/tracing/manifest.json
similarity index 100%
rename from mojo/services/tracing/manifest.json
rename to services/tracing/manifest.json
diff --git a/mojo/services/tracing/public/cpp/BUILD.gn b/services/tracing/public/cpp/BUILD.gn
similarity index 89%
rename from mojo/services/tracing/public/cpp/BUILD.gn
rename to services/tracing/public/cpp/BUILD.gn
index 74ec607..7fa6eab 100644
--- a/mojo/services/tracing/public/cpp/BUILD.gn
+++ b/services/tracing/public/cpp/BUILD.gn
@@ -15,7 +15,7 @@
   deps = [
     "//base",
     "//mojo/public/cpp/bindings",
-    "//mojo/services/tracing/public/interfaces",
     "//services/shell/public/cpp",
+    "//services/tracing/public/interfaces",
   ]
 }
diff --git a/mojo/services/tracing/public/cpp/switches.cc b/services/tracing/public/cpp/switches.cc
similarity index 92%
rename from mojo/services/tracing/public/cpp/switches.cc
rename to services/tracing/public/cpp/switches.cc
index 1b838e6..279c890 100644
--- a/mojo/services/tracing/public/cpp/switches.cc
+++ b/services/tracing/public/cpp/switches.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 "mojo/services/tracing/public/cpp/switches.h"
+#include "services/tracing/public/cpp/switches.h"
 
 namespace tracing {
 
diff --git a/mojo/services/tracing/public/cpp/switches.h b/services/tracing/public/cpp/switches.h
similarity index 79%
rename from mojo/services/tracing/public/cpp/switches.h
rename to services/tracing/public/cpp/switches.h
index 8a1e512..b127d56 100644
--- a/mojo/services/tracing/public/cpp/switches.h
+++ b/services/tracing/public/cpp/switches.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 MOJO_SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
-#define MOJO_SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
+#ifndef SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
+#define SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
 
 namespace tracing {
 
@@ -21,4 +21,4 @@
 
 }  // namespace tracing
 
-#endif  // MOJO_SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
+#endif  // SERVICES_TRACING_PUBLIC_CPP_SWITCHES_H_
diff --git a/mojo/services/tracing/public/cpp/trace_provider_impl.cc b/services/tracing/public/cpp/trace_provider_impl.cc
similarity index 97%
rename from mojo/services/tracing/public/cpp/trace_provider_impl.cc
rename to services/tracing/public/cpp/trace_provider_impl.cc
index 6ae0d8d9..08a80110 100644
--- a/mojo/services/tracing/public/cpp/trace_provider_impl.cc
+++ b/services/tracing/public/cpp/trace_provider_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
 
 #include <utility>
 
diff --git a/mojo/services/tracing/public/cpp/trace_provider_impl.h b/services/tracing/public/cpp/trace_provider_impl.h
similarity index 84%
rename from mojo/services/tracing/public/cpp/trace_provider_impl.h
rename to services/tracing/public/cpp/trace_provider_impl.h
index 5774911..975781b 100644
--- a/mojo/services/tracing/public/cpp/trace_provider_impl.h
+++ b/services/tracing/public/cpp/trace_provider_impl.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 MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
-#define MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
+#ifndef SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
+#define SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
 
 #include "base/macros.h"
 #include "base/memory/ref_counted_memory.h"
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
 
 namespace mojo {
 
@@ -48,4 +48,4 @@
 
 }  // namespace mojo
 
-#endif  // MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
+#endif  // SERVICES_TRACING_PUBLIC_CPP_TRACE_PROVIDER_IMPL_H_
diff --git a/mojo/services/tracing/public/cpp/tracing_impl.cc b/services/tracing/public/cpp/tracing_impl.cc
similarity index 94%
rename from mojo/services/tracing/public/cpp/tracing_impl.cc
rename to services/tracing/public/cpp/tracing_impl.cc
index c702191..349ccb5 100644
--- a/mojo/services/tracing/public/cpp/tracing_impl.cc
+++ b/services/tracing/public/cpp/tracing_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/services/tracing/public/cpp/tracing_impl.h"
+#include "services/tracing/public/cpp/tracing_impl.h"
 
 #include <utility>
 
@@ -14,7 +14,7 @@
 
 #ifdef NDEBUG
 #include "base/command_line.h"
-#include "mojo/services/tracing/public/cpp/switches.h"
+#include "services/tracing/public/cpp/switches.h"
 #endif
 
 namespace mojo {
diff --git a/mojo/services/tracing/public/cpp/tracing_impl.h b/services/tracing/public/cpp/tracing_impl.h
similarity index 82%
rename from mojo/services/tracing/public/cpp/tracing_impl.h
rename to services/tracing/public/cpp/tracing_impl.h
index 45ed8419..f3f034c 100644
--- a/mojo/services/tracing/public/cpp/tracing_impl.h
+++ b/services/tracing/public/cpp/tracing_impl.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
-#define MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
+#ifndef SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
+#define SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
 
 #include "base/macros.h"
-#include "mojo/services/tracing/public/cpp/trace_provider_impl.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
 #include "services/shell/public/cpp/interface_factory.h"
+#include "services/tracing/public/cpp/trace_provider_impl.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
 
 namespace mojo {
 
@@ -47,4 +47,4 @@
 
 }  // namespace mojo
 
-#endif  // MOJO_SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
+#endif  // SERVICES_TRACING_PUBLIC_CPP_TRACING_IMPL_H_
diff --git a/mojo/services/tracing/public/interfaces/BUILD.gn b/services/tracing/public/interfaces/BUILD.gn
similarity index 100%
rename from mojo/services/tracing/public/interfaces/BUILD.gn
rename to services/tracing/public/interfaces/BUILD.gn
diff --git a/mojo/services/tracing/public/interfaces/tracing.mojom b/services/tracing/public/interfaces/tracing.mojom
similarity index 100%
rename from mojo/services/tracing/public/interfaces/tracing.mojom
rename to services/tracing/public/interfaces/tracing.mojom
diff --git a/mojo/services/tracing/trace_data_sink.cc b/services/tracing/trace_data_sink.cc
similarity index 93%
rename from mojo/services/tracing/trace_data_sink.cc
rename to services/tracing/trace_data_sink.cc
index e608a745..b2789566 100644
--- a/mojo/services/tracing/trace_data_sink.cc
+++ b/services/tracing/trace_data_sink.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 "mojo/services/tracing/trace_data_sink.h"
+#include "services/tracing/trace_data_sink.h"
 
 #include <utility>
 
diff --git a/mojo/services/tracing/trace_data_sink.h b/services/tracing/trace_data_sink.h
similarity index 79%
rename from mojo/services/tracing/trace_data_sink.h
rename to services/tracing/trace_data_sink.h
index ce0b463..6862faa0 100644
--- a/mojo/services/tracing/trace_data_sink.h
+++ b/services/tracing/trace_data_sink.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 MOJO_SERVICES_TRACING_TRACE_DATA_SINK_H_
-#define MOJO_SERVICES_TRACING_TRACE_DATA_SINK_H_
+#ifndef SERVICES_TRACING_TRACE_DATA_SINK_H_
+#define SERVICES_TRACING_TRACE_DATA_SINK_H_
 
 #include <string>
 
@@ -28,4 +28,4 @@
 
 }  // namespace tracing
 
-#endif  // MOJO_SERVICES_TRACING_TRACE_DATA_SINK_H_
+#endif  // SERVICES_TRACING_TRACE_DATA_SINK_H_
diff --git a/mojo/services/tracing/trace_recorder_impl.cc b/services/tracing/trace_recorder_impl.cc
similarity index 92%
rename from mojo/services/tracing/trace_recorder_impl.cc
rename to services/tracing/trace_recorder_impl.cc
index 92dd95c4..f705792 100644
--- a/mojo/services/tracing/trace_recorder_impl.cc
+++ b/services/tracing/trace_recorder_impl.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "mojo/services/tracing/trace_recorder_impl.h"
+#include "services/tracing/trace_recorder_impl.h"
 
 #include <utility>
 
diff --git a/mojo/services/tracing/trace_recorder_impl.h b/services/tracing/trace_recorder_impl.h
similarity index 80%
rename from mojo/services/tracing/trace_recorder_impl.h
rename to services/tracing/trace_recorder_impl.h
index 55640e1..2e63e31c 100644
--- a/mojo/services/tracing/trace_recorder_impl.h
+++ b/services/tracing/trace_recorder_impl.h
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef MOJO_SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
-#define MOJO_SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
+#ifndef SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
+#define SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
 
 #include "base/macros.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/string.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
-#include "mojo/services/tracing/trace_data_sink.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/trace_data_sink.h"
 
 namespace tracing {
 
@@ -40,4 +40,4 @@
 
 }  // namespace tracing
 
-#endif  // MOJO_SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
+#endif  // SERVICES_TRACING_TRACE_RECORDER_IMPL_H_
diff --git a/services/tracing/tracing.gyp b/services/tracing/tracing.gyp
new file mode 100644
index 0000000..04aad5c
--- /dev/null
+++ b/services/tracing/tracing.gyp
@@ -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.
+
+{
+  'targets': [
+    {
+      'target_name': 'tracing_interfaces',
+      'type': 'none',
+      'variables': {
+        'mojom_files': [
+          'public/interfaces/tracing.mojom',
+        ],
+        'mojom_include_path': '<(DEPTH)/mojo/services',
+      },
+      'includes': [
+        '../../mojo/mojom_bindings_generator_explicit.gypi',
+      ],
+    },
+    {
+      # Technically, these should be in the mojo_services.gyp, but this causes
+      # a cycle since the ios generator can't have gyp files refer to each
+      # other, even if the targets don't form a cycle.
+      #
+      # GN version: //services/tracing:lib
+      'target_name': 'tracing_lib',
+      'type': 'static_library',
+      'dependencies': [
+        'tracing_public',
+        '../../mojo/mojo_edk.gyp:mojo_system_impl',
+        '../shell/shell.gyp:shell_public',
+      ],
+      'sources': [
+        'trace_data_sink.cc',
+        'trace_data_sink.h',
+        'trace_recorder_impl.cc',
+        'trace_recorder_impl.h',
+        'tracing_app.cc',
+        'tracing_app.h',
+      ],
+    },
+    {
+      # GN version: //mojo/services/public/cpp
+      'target_name': 'tracing_public',
+      'type': 'static_library',
+      'dependencies': [
+        'tracing_interfaces',
+        '../../mojo/mojo_edk.gyp:mojo_system_impl',
+        '../shell/shell.gyp:shell_public',
+      ],
+      'sources': [
+        'public/cpp/switches.cc',
+        'public/cpp/switches.h',
+        'public/cpp/tracing_impl.cc',
+        'public/cpp/tracing_impl.h',
+        'public/cpp/trace_provider_impl.cc',
+        'public/cpp/trace_provider_impl.h',
+      ],
+    },
+  ],
+}
diff --git a/mojo/services/tracing/tracing_app.cc b/services/tracing/tracing_app.cc
similarity index 99%
rename from mojo/services/tracing/tracing_app.cc
rename to services/tracing/tracing_app.cc
index c38bfad..845f6ba1 100644
--- a/mojo/services/tracing/tracing_app.cc
+++ b/services/tracing/tracing_app.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 "mojo/services/tracing/tracing_app.h"
+#include "services/tracing/tracing_app.h"
 
 #include <stddef.h>
 #include <stdint.h>
diff --git a/mojo/services/tracing/tracing_app.h b/services/tracing/tracing_app.h
similarity index 89%
rename from mojo/services/tracing/tracing_app.h
rename to services/tracing/tracing_app.h
index 740b31f..48b67e4 100644
--- a/mojo/services/tracing/tracing_app.h
+++ b/services/tracing/tracing_app.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 MOJO_SERVICES_TRACING_TRACING_APP_H_
-#define MOJO_SERVICES_TRACING_TRACING_APP_H_
+#ifndef SERVICES_TRACING_TRACING_APP_H_
+#define SERVICES_TRACING_TRACING_APP_H_
 
 #include <stdint.h>
 
@@ -13,11 +13,11 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/bindings/interface_ptr_set.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "mojo/services/tracing/public/interfaces/tracing.mojom.h"
-#include "mojo/services/tracing/trace_data_sink.h"
-#include "mojo/services/tracing/trace_recorder_impl.h"
 #include "services/shell/public/cpp/interface_factory.h"
 #include "services/shell/public/cpp/shell_client.h"
+#include "services/tracing/public/interfaces/tracing.mojom.h"
+#include "services/tracing/trace_data_sink.h"
+#include "services/tracing/trace_recorder_impl.h"
 
 namespace tracing {
 
@@ -78,4 +78,4 @@
 
 }  // namespace tracing
 
-#endif  // MOJO_SERVICES_TRACING_TRACING_APP_H_
+#endif  // SERVICES_TRACING_TRACING_APP_H_
diff --git a/skia/chromium_skia_defines.gypi b/skia/chromium_skia_defines.gypi
index 95437b2..2d7b97f 100644
--- a/skia/chromium_skia_defines.gypi
+++ b/skia/chromium_skia_defines.gypi
@@ -19,7 +19,6 @@
     # made to remove these defines as soon as practical. This is in contrast to
     # defines in SkUserConfig.h which are normally more permanent.
     'chromium_skia_defines': [
-      'SK_VERY_LEGACY_CREATE_TYPEFACE',
     ],
   },
 }
diff --git a/skia/ext/skia_utils_base.cc b/skia/ext/skia_utils_base.cc
index f026c07..335eb27 100644
--- a/skia/ext/skia_utils_base.cc
+++ b/skia/ext/skia_utils_base.cc
@@ -40,6 +40,24 @@
   return true;
 }
 
+bool ReadSkFontStyle(base::PickleIterator* iter, SkFontStyle* style) {
+  uint16_t reply_weight;
+  uint16_t reply_width;
+  uint16_t reply_slant;
+
+  if (!iter->ReadUInt16(&reply_weight) ||
+      !iter->ReadUInt16(&reply_width) ||
+      !iter->ReadUInt16(&reply_slant))
+    return false;
+
+  if (style) {
+    *style = SkFontStyle(reply_weight,
+                         reply_width,
+                         static_cast<SkFontStyle::Slant>(reply_slant));
+  }
+  return true;
+}
+
 bool WriteSkString(base::Pickle* pickle, const SkString& str) {
   return pickle->WriteData(str.c_str(), str.size());
 }
@@ -51,6 +69,12 @@
          WriteSkString(pickle, identity.fString);
 }
 
+bool WriteSkFontStyle(base::Pickle* pickle, SkFontStyle style) {
+  return pickle->WriteUInt16(style.weight()) &&
+         pickle->WriteUInt16(style.width()) &&
+         pickle->WriteUInt16(style.slant());
+}
+
 SkPixelGeometry ComputeDefaultPixelGeometry() {
     SkFontHost::LCDOrder order = SkFontHost::GetSubpixelOrder();
     if (SkFontHost::kNONE_LCDOrder == order) {
diff --git a/skia/ext/skia_utils_base.h b/skia/ext/skia_utils_base.h
index 77a9490b..60423dc 100644
--- a/skia/ext/skia_utils_base.h
+++ b/skia/ext/skia_utils_base.h
@@ -21,6 +21,10 @@
 SK_API bool ReadSkFontIdentity(base::PickleIterator* iter,
                                SkFontConfigInterface::FontIdentity* identity);
 
+// Return true if the pickle/iterator contains a SkFontStyle. If so, and if
+// style is not null, copy it into style.
+SK_API bool ReadSkFontStyle(base::PickleIterator* iter, SkFontStyle* style);
+
 // Return true if str can be written into the request pickle.
 SK_API bool WriteSkString(base::Pickle* pickle, const SkString& str);
 
@@ -29,6 +33,9 @@
     base::Pickle* pickle,
     const SkFontConfigInterface::FontIdentity& identity);
 
+// Return true if str can be written into the request pickle.
+SK_API bool WriteSkFontStyle(base::Pickle* pickle, SkFontStyle style);
+
 // Determine the default pixel geometry (for LCD) by querying the font host
 SK_API SkPixelGeometry ComputeDefaultPixelGeometry();
 
diff --git a/testing/buildbot/chromium.linux.json b/testing/buildbot/chromium.linux.json
index d447513..4d3cbfd 100644
--- a/testing/buildbot/chromium.linux.json
+++ b/testing/buildbot/chromium.linux.json
@@ -143,6 +143,18 @@
         "test": "components_browsertests"
       },
       {
+        "swarming": {
+          "can_use_on_swarming_builders": true,
+          "dimension_sets": [
+            {
+              "build.id": "KTU84P",
+              "product.board": "hammerhead"
+            }
+          ]
+        },
+        "test": "chrome_public_test"
+      },
+      {
         "args": [
           "--isolate_file_path=src/components/components_unittests.isolate"
         ],
@@ -238,9 +250,6 @@
         "test": "android_webview_test_apk"
       },
       {
-        "test": "chrome_public_test_apk"
-      },
-      {
         "test": "chrome_sync_shell_test_apk"
       },
       {
diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn
index 6d97aaf..f3ea127 100644
--- a/third_party/BUILD.gn
+++ b/third_party/BUILD.gn
@@ -8,7 +8,7 @@
 
 declare_args() {
   # Uses system libjpeg. If true, overrides use_libjpeg_turbo.
-  use_system_libjpeg = is_ios
+  use_system_libjpeg = false
 
   # Uses libjpeg_turbo as the jpeg implementation. Has no effect if
   # use_system_libjpeg is set.
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index d53bb35..4749007 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -1264,12 +1264,10 @@
 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/571773 inspector/console/worker-exception-message-contains-stack.html [ Failure Timeout Crash Pass ]
 crbug.com/551843 fast/text/fallback-traits-fixup.html [ NeedsManualRebaseline ]
 
 crbug.com/399951 http/tests/mime/javascript-mimetype-usecounters.html [ Pass Failure ]
 
-crbug.com/572710 [ Debug ] inspector/extensions/extensions-sidebar.html [ Timeout Pass ]
 crbug.com/602193 inspector/extensions/extensions-resources.html [ Pass Failure ]
 
 crbug.com/579493 http/tests/security/xss-DENIED-xsl-document-securityOrigin.xml [ Timeout ]
@@ -1539,3 +1537,10 @@
 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 d5c2b05..0a61e3d 100644
--- a/third_party/WebKit/LayoutTests/W3CImportExpectations
+++ b/third_party/WebKit/LayoutTests/W3CImportExpectations
@@ -289,7 +289,8 @@
 ## Owners: jsbell@chromium.org
 # imported/web-platform-tests/user-timing [ Pass ]
 imported/web-platform-tests/vibration [ Skip ]
-imported/web-platform-tests/web-animations [ Skip ]
+## Owners: suzyh@chromium.org
+# imported/web-platform-tests/web-animations [ Pass ]
 imported/web-platform-tests/webaudio [ Skip ]
 imported/web-platform-tests/webdriver [ Skip ]
 imported/web-platform-tests/webgl [ Skip ]
@@ -319,6 +320,7 @@
 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/animations/composition/backdrop-filter-composition.html b/third_party/WebKit/LayoutTests/animations/composition/backdrop-filter-composition.html
new file mode 100644
index 0000000..5956f6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/composition/backdrop-filter-composition.html
@@ -0,0 +1,171 @@
+<!DOCTYPE html>
+<meta charset="UTF-8">
+<body>
+<script src="../interpolation/resources/interpolation-test.js"></script>
+<script>
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'blur(10px)',
+  addFrom: 'blur(40px)',
+  addTo: 'blur(90px)',
+}, [
+  {at: -0.5, is: 'blur(25px)'},
+  {at: 0, is: 'blur(50px)'},
+  {at: 0.25, is: 'blur(62.5px)'},
+  {at: 0.5, is: 'blur(75px)'},
+  {at: 0.75, is: 'blur(87.5px)'},
+  {at: 1, is: 'blur(100px)'},
+  {at: 1.5, is: 'blur(125px)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'sepia(0.5)',
+  addFrom: 'sepia(0.5)',
+  replaceTo: 'sepia(0)',
+}, [
+  {at: -0.5, is: 'sepia(1)'},
+  {at: 0, is: 'sepia(1)'},
+  {at: 0.25, is: 'sepia(0.75)'},
+  {at: 0.5, is: 'sepia(0.5)'},
+  {at: 0.75, is: 'sepia(0.25)'},
+  {at: 1, is: 'sepia(0)'},
+  {at: 1.5, is: 'sepia(0)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'brightness(0.25)',
+  replaceFrom: 'brightness(0.5)',
+  addTo: 'brightness(1.25)',
+}, [
+  {at: -0.5, is: 'brightness(0)'},
+  {at: 0, is: 'brightness(0.5)'},
+  {at: 0.25, is: 'brightness(0.75)'},
+  {at: 0.5, is: 'brightness(1)'},
+  {at: 0.75, is: 'brightness(1.25)'},
+  {at: 1, is: 'brightness(1.5)'},
+  {at: 1.5, is: 'brightness(2)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'invert(0.5) saturate(1)',
+  addFrom: 'invert(1) saturate(2)',
+  addTo: 'invert(25%) saturate(3)',
+}, [
+  {at: -0.5, is: 'invert(1) saturate(2.5)'},
+  {at: 0, is: 'invert(1) saturate(3)'},
+  {at: 0.25, is: 'invert(1) saturate(3.25)'},
+  {at: 0.5, is: 'invert(1) saturate(3.5)'},
+  {at: 0.75, is: 'invert(0.9375) saturate(3.75)'},
+  {at: 1, is: 'invert(0.75) saturate(4)'},
+  {at: 1.5, is: 'invert(0.375) saturate(4.5)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'invert(0.5)',
+  addFrom: 'invert(1) saturate(200%)',
+  addTo: 'invert(25%) saturate(3) contrast(50%)',
+}, [
+  {at: -0.5, is: 'invert(1) saturate(1.5) contrast(1.25)'},
+  {at: 0, is: 'invert(1) saturate(2)'},
+  {at: 0.25, is: 'invert(1) saturate(2.25) contrast(0.875)'},
+  {at: 0.5, is: 'invert(1) saturate(2.5) contrast(0.75)'},
+  {at: 0.75, is: 'invert(0.9375) saturate(2.75) contrast(0.625)'},
+  {at: 1, is: 'invert(0.75) saturate(3) contrast(0.5)'},
+  {at: 1.5, is: 'invert(0.375) saturate(3.5) contrast(0.25)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'invert(0.5)',
+  addFrom: 'none',
+  addTo: 'invert(25%) saturate(3) contrast(50%)',
+}, [
+  {at: -0.5, is: 'invert(0.375) saturate(0) contrast(1.25)'},
+  {at: 0, is: 'invert(0.5)'},
+  {at: 0.25, is: 'invert(0.5625) saturate(1.5) contrast(0.875)'},
+  {at: 0.5, is: 'invert(0.625) saturate(2) contrast(0.75)'},
+  {at: 0.75, is: 'invert(0.6875) saturate(2.5) contrast(0.625)'},
+  {at: 1, is: 'invert(0.75) saturate(3) contrast(0.5)'},
+  {at: 1.5, is: 'invert(0.875) saturate(4) contrast(0.25)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'invert(0.5)',
+  addFrom: 'invert(1) saturate(200%)',
+  addTo: 'none',
+}, [
+  {at: -0.5, is: 'invert(1) saturate(2.5)'},
+  {at: 0, is: 'invert(1) saturate(2)'},
+  {at: 0.25, is: 'invert(1) saturate(1.75)'},
+  {at: 0.5, is: 'invert(1) saturate(1.5)'},
+  {at: 0.75, is: 'invert(0.75) saturate(1.25)'},
+  {at: 1, is: 'invert(0.5)'},
+  {at: 1.5, is: 'invert(0) saturate(0.5)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'none',
+  addFrom: 'invert(1) saturate(200%)',
+  addTo: 'invert(25%) saturate(3) contrast(50%)',
+}, [
+  {at: -0.5, is: 'invert(1) saturate(1.5) contrast(1.25)'},
+  {at: 0, is: 'invert(1) saturate(2)'},
+  {at: 0.25, is: 'invert(0.8125) saturate(2.25) contrast(0.875)'},
+  {at: 0.5, is: 'invert(0.625) saturate(2.5) contrast(0.75)'},
+  {at: 0.75, is: 'invert(0.4375) saturate(2.75) contrast(0.625)'},
+  {at: 1, is: 'invert(0.25) saturate(3) contrast(0.5)'},
+  {at: 1.5, is: 'invert(0) saturate(3.5) contrast(0.25)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'grayscale(25%) blur(10px)',
+  addFrom: 'grayscale(50%) blur(10px)',
+  addTo: 'blur(10px)',
+}, [
+  {at: -0.5, is: 'grayscale(0.75) blur(20px)'},
+  {at: 0, is: 'grayscale(0.75) blur(20px)'},
+  {at: 0.25, is: 'grayscale(0.75) blur(20px)'},
+  {at: 0.5, is: 'blur(10px)'},
+  {at: 0.75, is: 'blur(10px)'},
+  {at: 1, is: 'blur(10px)'},
+  {at: 1.5, is: 'blur(10px)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'blur(10px)',
+  addFrom: 'grayscale(50%) blur(10px)',
+  addTo: 'grayscale(25%) blur(10px)',
+}, [
+  {at: -0.5, is: 'grayscale(0.625) blur(10px)'},
+  {at: 0, is: 'grayscale(0.5) blur(10px)'},
+  {at: 0.25, is: 'grayscale(0.4375) blur(10px)'},
+  {at: 0.5, is: 'grayscale(0.375) blur(10px)'},
+  {at: 0.75, is: 'grayscale(0.3125) blur(10px)'},
+  {at: 1, is: 'grayscale(0.25) blur(10px)'},
+  {at: 1.5, is: 'grayscale(0.125) blur(10px)'},
+]);
+
+assertComposition({
+  property: 'backdrop-filter',
+  underlying: 'url(#a) grayscale(50%) blur(20px)',
+  addFrom: 'url(#a) grayscale(50%) blur(30px)',
+  addTo: 'url(#a) grayscale(25%) blur(40px)',
+}, [
+  {at: -0.5, is: 'url("#a") grayscale(0.5) blur(30px)'},
+  {at: 0, is: 'url("#a") grayscale(0.5) blur(30px)'},
+  {at: 0.25, is: 'url("#a") grayscale(0.5) blur(30px)'},
+  {at: 0.5, is: 'url("#a") grayscale(0.25) blur(40px)'},
+  {at: 0.75, is: 'url("#a") grayscale(0.25) blur(40px)'},
+  {at: 1, is: 'url("#a") grayscale(0.25) blur(40px)'},
+  {at: 1.5, is: 'url("#a") grayscale(0.25) blur(40px)'},
+]);
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation-expected.txt
index 5977c871..92c7167 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
-PASS CSS Transitions: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
+PASS CSS Transitions: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(-10deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(6deg)] 
@@ -43,14 +43,20 @@
 PASS CSS Transitions: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (0.6) is [blur(10px)] 
 PASS CSS Transitions: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Transitions: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1.5) is [blur(10px)] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (-0.5) is [opacity(1) hue-rotate(-90deg)] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0) is [none] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.25) is [opacity(0.875) hue-rotate(45deg)] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.5) is [opacity(0.75) hue-rotate(90deg)] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1) is [opacity(0.5) hue-rotate(180deg)] 
+PASS CSS Transitions: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1.5) is [opacity(0.25) hue-rotate(270deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (-0.5) is [blur(4px) hue-rotate(-90deg)] 
-FAIL CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] assert_equals: expected "blur ( 6px ) hue - rotate ( 0deg ) " but got "blur ( 6px ) "
+PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] 
 PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.25) is [blur(7px) hue-rotate(45deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.5) is [blur(8px) hue-rotate(90deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1) is [blur(10px) hue-rotate(180deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1.5) is [blur(12px) hue-rotate(270deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (-0.5) is [hue-rotate(-90deg)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.25) is [hue-rotate(45deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.5) is [hue-rotate(90deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (1) is [hue-rotate(180deg)] 
@@ -59,26 +65,26 @@
 PASS CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0) is [hue-rotate(180deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.25) is [hue-rotate(135deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.5) is [hue-rotate(90deg)] 
-FAIL CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1.5) is [hue-rotate(-90deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (-1) is [blur(0px)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] assert_equals: expected "blur ( 0px ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (0.5) is [blur(5px)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [blur(10px)] at (1.5) is [blur(15px)] 
 PASS CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (-1) is [brightness(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (0) is [brightness(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (0.5) is [brightness(0.5)] 
-FAIL CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] assert_equals: expected "brightness ( 1 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [brightness(0)] to [none] at (1.5) is [brightness(1.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (-1) is [contrast(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (0) is [contrast(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (0.5) is [contrast(0.5)] 
-FAIL CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] assert_equals: expected "contrast ( 1 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [contrast(0)] to [none] at (1.5) is [contrast(1.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgba(0, 0, 0, 0) -20px -10px 0px)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0) is [none] 
-PASS CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] 
+FAIL CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] assert_equals: expected "drop - shadow ( rgba ( 0 , 128 , 0 , 0.5 ) 10px 5px 0px ) " but got "drop - shadow ( rgba ( 0 , 127 , 0 , 0.5 ) 10px 5px 0px ) "
 PASS CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 192, 0) 30px 15px 0px)] 
 PASS CSS Transitions: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgb(255, 255, 255) -20px -10px 0px)] 
@@ -87,32 +93,32 @@
 PASS CSS Transitions: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Transitions: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 65, 0) 30px 15px 0px)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (-1) is [grayscale(0)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] assert_equals: expected "grayscale ( 0 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (0.5) is [grayscale(0.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (1) is [grayscale(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [grayscale(1)] at (1.5) is [grayscale(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (-1) is [hue-rotate(-360deg)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0.5) is [hue-rotate(180deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1) is [hue-rotate(360deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1.5) is [hue-rotate(540deg)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (-1) is [invert(0)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] assert_equals: expected "invert ( 0 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (0.5) is [invert(0.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (1) is [invert(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [invert(1)] at (1.5) is [invert(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (-1) is [opacity(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (0) is [opacity(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (0.5) is [opacity(0.5)] 
-FAIL CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] assert_equals: expected "opacity ( 1 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [opacity(0)] to [none] at (1.5) is [opacity(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (-1) is [saturate(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (0) is [saturate(0)] 
 PASS CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (0.5) is [saturate(0.5)] 
-FAIL CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] assert_equals: expected "saturate ( 1 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [saturate(0)] to [none] at (1.5) is [saturate(1.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (-1) is [sepia(0)] 
-FAIL CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] assert_equals: expected "sepia ( 0 ) " but got "none "
+PASS CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [none] to [sepia(1)] at (1.5) is [sepia(1)] 
@@ -135,12 +141,12 @@
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Transitions: property <backdrop-filter> from [initial] to [sepia(1)] at (1.5) is [sepia(1)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
-PASS CSS Animations: property <backdrop-filter> from [] to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
+PASS CSS Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
 PASS CSS Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(-10deg)] 
 PASS CSS Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(6deg)] 
@@ -178,14 +184,20 @@
 PASS CSS Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (0.6) is [blur(10px)] 
 PASS CSS Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1.5) is [blur(10px)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (-0.5) is [opacity(1) hue-rotate(-90deg)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0) is [none] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.25) is [opacity(0.875) hue-rotate(45deg)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.5) is [opacity(0.75) hue-rotate(90deg)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1) is [opacity(0.5) hue-rotate(180deg)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1.5) is [opacity(0.25) hue-rotate(270deg)] 
 PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (-0.5) is [blur(4px) hue-rotate(-90deg)] 
-FAIL CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] assert_equals: expected "blur ( 6px ) hue - rotate ( 0deg ) " but got "blur ( 6px ) "
+PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] 
 PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.25) is [blur(7px) hue-rotate(45deg)] 
 PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.5) is [blur(8px) hue-rotate(90deg)] 
 PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1) is [blur(10px) hue-rotate(180deg)] 
 PASS CSS Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1.5) is [blur(12px) hue-rotate(270deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (-0.5) is [hue-rotate(-90deg)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.25) is [hue-rotate(45deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.5) is [hue-rotate(90deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (1) is [hue-rotate(180deg)] 
@@ -194,26 +206,26 @@
 PASS CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0) is [hue-rotate(180deg)] 
 PASS CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.25) is [hue-rotate(135deg)] 
 PASS CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.5) is [hue-rotate(90deg)] 
-FAIL CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1.5) is [hue-rotate(-90deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (-1) is [blur(0px)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] assert_equals: expected "blur ( 0px ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0.5) is [blur(5px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [blur(10px)] at (1.5) is [blur(15px)] 
 PASS CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (-1) is [brightness(0)] 
 PASS CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (0) is [brightness(0)] 
 PASS CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (0.5) is [brightness(0.5)] 
-FAIL CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] assert_equals: expected "brightness ( 1 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1.5) is [brightness(1.5)] 
 PASS CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (-1) is [contrast(0)] 
 PASS CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (0) is [contrast(0)] 
 PASS CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (0.5) is [contrast(0.5)] 
-FAIL CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] assert_equals: expected "contrast ( 1 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1.5) is [contrast(1.5)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgba(0, 0, 0, 0) -20px -10px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0) is [none] 
-PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] 
+PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 128, 0, 0.501961) 10px 5px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 192, 0) 30px 15px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgb(255, 255, 255) -20px -10px 0px)] 
@@ -222,32 +234,32 @@
 PASS CSS Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 65, 0) 30px 15px 0px)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (-1) is [grayscale(0)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] assert_equals: expected "grayscale ( 0 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0.5) is [grayscale(0.5)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (1) is [grayscale(1)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (1.5) is [grayscale(1)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (-1) is [hue-rotate(-360deg)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0.5) is [hue-rotate(180deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1) is [hue-rotate(360deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1.5) is [hue-rotate(540deg)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (-1) is [invert(0)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] assert_equals: expected "invert ( 0 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (0.5) is [invert(0.5)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (1) is [invert(1)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [invert(1)] at (1.5) is [invert(1)] 
 PASS CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (-1) is [opacity(0)] 
 PASS CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (0) is [opacity(0)] 
 PASS CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (0.5) is [opacity(0.5)] 
-FAIL CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] assert_equals: expected "opacity ( 1 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1.5) is [opacity(1)] 
 PASS CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (-1) is [saturate(0)] 
 PASS CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (0) is [saturate(0)] 
 PASS CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (0.5) is [saturate(0.5)] 
-FAIL CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] assert_equals: expected "saturate ( 1 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1.5) is [saturate(1.5)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (-1) is [sepia(0)] 
-FAIL CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] assert_equals: expected "sepia ( 0 ) " but got "none "
+PASS CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Animations: property <backdrop-filter> from [none] to [sepia(1)] at (1.5) is [sepia(1)] 
@@ -270,6 +282,12 @@
 PASS CSS Animations: property <backdrop-filter> from [initial] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Animations: property <backdrop-filter> from [initial] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Animations: property <backdrop-filter> from [initial] to [sepia(1)] at (1.5) is [sepia(1)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
+PASS Web Animations: property <backdrop-filter> from neutral to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
 PASS Web Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(-10deg)] 
 PASS Web Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [initial] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(6deg)] 
@@ -307,14 +325,20 @@
 PASS Web Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (0.6) is [blur(10px)] 
 PASS Web Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1) is [blur(10px)] 
 PASS Web Animations: property <backdrop-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1.5) is [blur(10px)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (-0.5) is [opacity(1) hue-rotate(-90deg)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0) is [none] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.25) is [opacity(0.875) hue-rotate(45deg)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.5) is [opacity(0.75) hue-rotate(90deg)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1) is [opacity(0.5) hue-rotate(180deg)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1.5) is [opacity(0.25) hue-rotate(270deg)] 
 PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (-0.5) is [blur(4px) hue-rotate(-90deg)] 
-FAIL Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] assert_equals: expected "blur ( 6px ) hue - rotate ( 0deg ) " but got "blur ( 6px ) "
+PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] 
 PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.25) is [blur(7px) hue-rotate(45deg)] 
 PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.5) is [blur(8px) hue-rotate(90deg)] 
 PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1) is [blur(10px) hue-rotate(180deg)] 
 PASS Web Animations: property <backdrop-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1.5) is [blur(12px) hue-rotate(270deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (-0.5) is [hue-rotate(-90deg)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.25) is [hue-rotate(45deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (0.5) is [hue-rotate(90deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(180deg)] at (1) is [hue-rotate(180deg)] 
@@ -323,26 +347,26 @@
 PASS Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0) is [hue-rotate(180deg)] 
 PASS Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.25) is [hue-rotate(135deg)] 
 PASS Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (0.5) is [hue-rotate(90deg)] 
-FAIL Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] 
 PASS Web Animations: property <backdrop-filter> from [hue-rotate(180deg)] to [none] at (1.5) is [hue-rotate(-90deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (-1) is [blur(0px)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] assert_equals: expected "blur ( 0px ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (0.5) is [blur(5px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (1) is [blur(10px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [blur(10px)] at (1.5) is [blur(15px)] 
 PASS Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (-1) is [brightness(0)] 
 PASS Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (0) is [brightness(0)] 
 PASS Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (0.5) is [brightness(0.5)] 
-FAIL Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] assert_equals: expected "brightness ( 1 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1) is [none] 
 PASS Web Animations: property <backdrop-filter> from [brightness(0)] to [none] at (1.5) is [brightness(1.5)] 
 PASS Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (-1) is [contrast(0)] 
 PASS Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (0) is [contrast(0)] 
 PASS Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (0.5) is [contrast(0.5)] 
-FAIL Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] assert_equals: expected "contrast ( 1 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1) is [none] 
 PASS Web Animations: property <backdrop-filter> from [contrast(0)] to [none] at (1.5) is [contrast(1.5)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgba(0, 0, 0, 0) -20px -10px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0) is [none] 
-PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] 
+PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 128, 0, 0.501961) 10px 5px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 192, 0) 30px 15px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgb(255, 255, 255) -20px -10px 0px)] 
@@ -351,32 +375,32 @@
 PASS Web Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 65, 0) 30px 15px 0px)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (-1) is [grayscale(0)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] assert_equals: expected "grayscale ( 0 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (0.5) is [grayscale(0.5)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (1) is [grayscale(1)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [grayscale(1)] at (1.5) is [grayscale(1)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (-1) is [hue-rotate(-360deg)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (0.5) is [hue-rotate(180deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1) is [hue-rotate(360deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [hue-rotate(360deg)] at (1.5) is [hue-rotate(540deg)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (-1) is [invert(0)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] assert_equals: expected "invert ( 0 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (0.5) is [invert(0.5)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (1) is [invert(1)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [invert(1)] at (1.5) is [invert(1)] 
 PASS Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (-1) is [opacity(0)] 
 PASS Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (0) is [opacity(0)] 
 PASS Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (0.5) is [opacity(0.5)] 
-FAIL Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] assert_equals: expected "opacity ( 1 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1) is [none] 
 PASS Web Animations: property <backdrop-filter> from [opacity(0)] to [none] at (1.5) is [opacity(1)] 
 PASS Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (-1) is [saturate(0)] 
 PASS Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (0) is [saturate(0)] 
 PASS Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (0.5) is [saturate(0.5)] 
-FAIL Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] assert_equals: expected "saturate ( 1 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1) is [none] 
 PASS Web Animations: property <backdrop-filter> from [saturate(0)] to [none] at (1.5) is [saturate(1.5)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (-1) is [sepia(0)] 
-FAIL Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] assert_equals: expected "sepia ( 0 ) " but got "none "
+PASS Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0) is [none] 
 PASS Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (1) is [sepia(1)] 
 PASS Web Animations: property <backdrop-filter> from [none] to [sepia(1)] at (1.5) is [sepia(1)] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation.html
index a54b3f62..5654eec 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/backdrop-filter-interpolation.html
@@ -30,7 +30,7 @@
 <script>
 assertInterpolation({
   property: 'backdrop-filter',
-  from: '',
+  from: neutralKeyframe,
   to: 'hue-rotate(20deg)',
 }, [
   {at: -0.5, is: 'hue-rotate(5deg)'},
@@ -118,11 +118,24 @@
 // Partially matching lists:
 assertInterpolation({
   property: 'backdrop-filter',
+  from: 'none',
+  to: 'opacity(0.5) hue-rotate(180deg)',
+}, [
+  {at: -0.5, is: 'opacity(1) hue-rotate(-90deg)'},
+  {at: 0, is: 'none'},
+  {at: 0.25, is: 'opacity(0.875) hue-rotate(45deg)'},
+  {at: 0.5, is: 'opacity(0.75) hue-rotate(90deg)'},
+  {at: 1, is: 'opacity(0.5) hue-rotate(180deg)'},
+  {at: 1.5, is: 'opacity(0.25) hue-rotate(270deg)'},
+]);
+
+assertInterpolation({
+  property: 'backdrop-filter',
   from: 'blur(6px)',
   to: 'blur(10px) hue-rotate(180deg)'
 }, [
   {at: -0.5, is: 'blur(4px) hue-rotate(-90deg)'},
-  {at: 0, is: 'blur(6px) hue-rotate(0deg)'},
+  {at: 0, is: 'blur(6px)'},
   {at: 0.25, is: 'blur(7px) hue-rotate(45deg)'},
   {at: 0.5, is: 'blur(8px) hue-rotate(90deg)'},
   {at: 1, is: 'blur(10px) hue-rotate(180deg)'},
@@ -135,7 +148,7 @@
   to: 'hue-rotate(180deg)'
 }, [
   {at: -0.5, is: 'hue-rotate(-90deg)'},
-  {at: 0, is: 'hue-rotate(0deg)'},
+  {at: 0, is: 'none'},
   {at: 0.25, is: 'hue-rotate(45deg)'},
   {at: 0.5, is: 'hue-rotate(90deg)'},
   {at: 1, is: 'hue-rotate(180deg)'},
@@ -151,7 +164,7 @@
   {at: 0, is: 'hue-rotate(180deg)'},
   {at: 0.25, is: 'hue-rotate(135deg)'},
   {at: 0.5, is: 'hue-rotate(90deg)'},
-  {at: 1, is: 'hue-rotate(0deg)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'hue-rotate(-90deg)'},
 ]);
 
@@ -162,7 +175,7 @@
   to: 'blur(10px)'
 }, [
   {at: -1, is: 'blur(0px)'}, // Negative values are not allowed.
-  {at: 0, is: 'blur(0px)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'blur(5px)'},
   {at: 1, is: 'blur(10px)'},
   {at: 1.5, is: 'blur(15px)'}
@@ -176,7 +189,7 @@
   {at: -1, is: 'brightness(0)'}, // Negative values are not allowed.
   {at: 0, is: 'brightness(0)'},
   {at: 0.5, is: 'brightness(0.5)'},
-  {at: 1, is: 'brightness(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'brightness(1.5)'}
 ]);
 
@@ -188,7 +201,7 @@
   {at: -1, is: 'contrast(0)'}, // Negative values are not allowed.
   {at: 0, is: 'contrast(0)'},
   {at: 0.5, is: 'contrast(0.5)'},
-  {at: 1, is: 'contrast(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'contrast(1.5)'}
 ]);
 
@@ -199,7 +212,7 @@
 }, [
   {at: -1, is: 'drop-shadow(-20px -10px transparent)'},
   {at: 0, is: 'none'},
-  {at: 0.5, is: 'drop-shadow(10px 5px rgba(0, 127, 0, 0.5))'},
+  {at: 0.5, is: 'drop-shadow(10px 5px rgba(0, 128, 0, 0.5))'},
   {at: 1, is: 'drop-shadow(20px 10px green)'},
   {at: 1.5, is: 'drop-shadow(30px 15px #00C000)'}
 ]);
@@ -222,7 +235,7 @@
   to: 'grayscale(1)'
 }, [
   {at: -1, is: 'grayscale(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'grayscale(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'grayscale(0.5)'},
   {at: 1, is: 'grayscale(1)'},
   {at: 1.5, is: 'grayscale(1)'} // Should clamp values to 1.
@@ -234,7 +247,7 @@
   to: 'hue-rotate(360deg)'
 }, [
   {at: -1, is: 'hue-rotate(-360deg)'},
-  {at: 0, is: 'hue-rotate(0deg)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'hue-rotate(180deg)'},
   {at: 1, is: 'hue-rotate(360deg)'},
   {at: 1.5, is: 'hue-rotate(540deg)'}
@@ -246,7 +259,7 @@
   to: 'invert(1)'
 }, [
   {at: -1, is: 'invert(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'invert(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'invert(0.5)'},
   {at: 1, is: 'invert(1)'},
   {at: 1.5, is: 'invert(1)'} // Should clamp values to 1.
@@ -260,7 +273,7 @@
   {at: -1, is: 'opacity(0)'}, // Negative values are not allowed.
   {at: 0, is: 'opacity(0)'},
   {at: 0.5, is: 'opacity(0.5)'},
-  {at: 1, is: 'opacity(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'opacity(1)'} // Should clamp values to 1.
 ]);
 
@@ -272,7 +285,7 @@
   {at: -1, is: 'saturate(0)'}, // Negative values are not allowed.
   {at: 0, is: 'saturate(0)'},
   {at: 0.5, is: 'saturate(0.5)'},
-  {at: 1, is: 'saturate(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'saturate(1.5)'}
 ]);
 
@@ -282,7 +295,7 @@
   to: 'sepia(1)'
 }, [
   {at: -1, is: 'sepia(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'sepia(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'sepia(0.5)'},
   {at: 1, is: 'sepia(1)'},
   {at: 1.5, is: 'sepia(1)'} // Should clamp values to 1.
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/background-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/background-color-interpolation.html
index 45c0379..68f67fd 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/background-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/background-color-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'background-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -0.3, is: 'rgb(0, 0, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/background-image-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/background-image-interpolation.html
index 145c906..181dac42 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/background-image-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/background-image-interpolation.html
@@ -26,7 +26,7 @@
 var to = 'url(../resources/green-100.png)';
 assertInterpolation({
   property: 'background-image',
-  from: '',
+  from: neutralKeyframe,
   to: to,
 }, [
   {at: -0.3, is: from},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/background-position-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/background-position-interpolation.html
index c384e9e..0276755 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/background-position-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/background-position-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'background-position',
-  from: '',
+  from: neutralKeyframe,
   to: '80px 80px, 80px 80px, 80px 80px, 80px 80px',
 }, [
   {at: -0.25, is: '30px 30px, 30px 30px, 30px 30px, 30px 30px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/background-position-origin-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/background-position-origin-interpolation.html
index 14ccc923..fb54deae 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/background-position-origin-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/background-position-origin-interpolation.html
@@ -28,7 +28,7 @@
 // neutral
 assertInterpolation({
   property: 'background-position',
-  from: '',
+  from: neutralKeyframe,
   to: 'left 20px top 20px',
 }, [
   {at: 0, is: '10px 10px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/background-size-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/background-size-interpolation.html
index e3ffdc0..b6a1cd9 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/background-size-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/background-size-interpolation.html
@@ -28,7 +28,7 @@
 // neutral
 assertInterpolation({
   property: 'background-size',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px, 0px 0px',
 }, [
   {at: -0.25, is: ' 7.5px  7.5px, 12.5px 12.5px,  7.5px  7.5px, 12.5px 12.5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-color-interpolation.html
index d952c0c..ddc7cf8 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-color-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'border-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'orange',
 }, [
   {at: -0.3, is: 'rgb(0, 0, 181)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-outset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-outset-interpolation.html
index 86e4868..934ee21b 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-outset-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-outset-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'border-image-outset',
-  from: '',
+  from: neutralKeyframe,
   to: '2px',
 }, [
   {at: -0.3, is: '0.7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-slice-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-slice-interpolation.html
index 2dc009d..58a477d 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-slice-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-slice-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'border-image-slice',
-  from: '',
+  from: neutralKeyframe,
   to: '10%',
 }, [
   {at: -0.3, is: '23%'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation-expected.txt
index e1f5860..d049e82 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
-PASS CSS Transitions: property <border-image-source> from [] to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
+PASS CSS Transitions: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0.3) is [url(file:///.../green-100.png)] 
@@ -56,13 +56,13 @@
 FAIL CSS Transitions: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (0.6) is [linear-gradient(45deg, blue, orange)] assert_equals: expected "- webkit - cross - fade ( linear - gradient ( - 45deg , red , yellow ) , linear - gradient ( 45deg , blue , orange ) , 0.6 ) " but got "linear - gradient ( 45deg , blue , orange ) "
 PASS CSS Transitions: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1) is [linear-gradient(45deg, blue, orange)] 
 PASS CSS Transitions: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1.5) is [linear-gradient(45deg, blue, orange)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
-PASS CSS Animations: property <border-image-source> from [] to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
+PASS CSS Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
 PASS CSS Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (-0.3) is [none] 
 PASS CSS Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0) is [none] 
 PASS CSS Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0.3) is [none] 
@@ -112,6 +112,13 @@
 PASS CSS Animations: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (0.6) is [-webkit-cross-fade(linear-gradient(-45deg, red, yellow), linear-gradient(45deg, blue, orange), 0.6)] 
 PASS CSS Animations: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1) is [linear-gradient(45deg, blue, orange)] 
 PASS CSS Animations: property <border-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1.5) is [linear-gradient(45deg, blue, orange)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
+PASS Web Animations: property <border-image-source> from neutral to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
 PASS Web Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (-0.3) is [none] 
 PASS Web Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0) is [none] 
 PASS Web Animations: property <border-image-source> from [initial] to [url(../resources/green-100.png)] at (0.3) is [none] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation.html
index f43e821..8eca8e3 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-source-interpolation.html
@@ -39,7 +39,7 @@
 
 // neutral
 assertCrossfadeInterpolation({
-  from: '',
+  from: neutralKeyframe,
   fromComputed: 'url(../resources/stripes-100.png)',
   to: 'url(../resources/green-100.png)',
 });
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
index 42424a7f..d437e1b8 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation-expected.txt
@@ -1,13 +1,13 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (-0.3) is [7px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (0) is [10px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (0.3) is [13px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (0.6) is [16px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (1) is [20px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (1.5) is [25px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (5) is [60px] 
-PASS CSS Transitions: property <border-image-width> from [] to [20px] at (10) is [110px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (-0.3) is [7px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (0) is [10px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (0.3) is [13px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (0.6) is [16px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (1) is [20px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (1.5) is [25px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (5) is [60px] 
+PASS CSS Transitions: property <border-image-width> from neutral to [20px] at (10) is [110px] 
 PASS CSS Transitions: property <border-image-width> from [initial] to [20px] at (-0.3) is [20px] 
 PASS CSS Transitions: property <border-image-width> from [initial] to [20px] at (0) is [20px] 
 PASS CSS Transitions: property <border-image-width> from [initial] to [20px] at (0.3) is [20px] 
@@ -116,14 +116,14 @@
 PASS CSS Transitions: property <border-image-width> from [10] to [20%] at (0.6) is [20%] 
 PASS CSS Transitions: property <border-image-width> from [10] to [20%] at (1) is [20%] 
 PASS CSS Transitions: property <border-image-width> from [10] to [20%] at (1.5) is [20%] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (-0.3) is [7px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (0) is [10px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (0.3) is [13px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (0.6) is [16px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (1) is [20px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (1.5) is [25px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (5) is [60px] 
-PASS CSS Animations: property <border-image-width> from [] to [20px] at (10) is [110px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (-0.3) is [7px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (0) is [10px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (0.3) is [13px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (0.6) is [16px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (1) is [20px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (1.5) is [25px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (5) is [60px] 
+PASS CSS Animations: property <border-image-width> from neutral to [20px] at (10) is [110px] 
 PASS CSS Animations: property <border-image-width> from [initial] to [20px] at (-0.3) is [1] 
 PASS CSS Animations: property <border-image-width> from [initial] to [20px] at (0) is [1] 
 PASS CSS Animations: property <border-image-width> from [initial] to [20px] at (0.3) is [1] 
@@ -232,6 +232,14 @@
 PASS CSS Animations: property <border-image-width> from [10] to [20%] at (0.6) is [20%] 
 PASS CSS Animations: property <border-image-width> from [10] to [20%] at (1) is [20%] 
 PASS CSS Animations: property <border-image-width> from [10] to [20%] at (1.5) is [20%] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (-0.3) is [7px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (0) is [10px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (0.3) is [13px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (0.6) is [16px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (1) is [20px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (1.5) is [25px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (5) is [60px] 
+PASS Web Animations: property <border-image-width> from neutral to [20px] at (10) is [110px] 
 PASS Web Animations: property <border-image-width> from [initial] to [20px] at (-0.3) is [1] 
 PASS Web Animations: property <border-image-width> from [initial] to [20px] at (0) is [1] 
 PASS Web Animations: property <border-image-width> from [initial] to [20px] at (0.3) is [1] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation.html
index 87250a20..1dc7d25 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-image-width-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'border-image-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is:   '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-radius-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-radius-interpolation.html
index f14076f..0da4ecd3 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-radius-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-radius-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'border-radius',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-spacing-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-spacing-interpolation.html
index 7ec1269..b159a35 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-spacing-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-spacing-interpolation.html
@@ -38,7 +38,7 @@
 <script>
 assertInterpolation({
   property: 'border-spacing',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px 7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/border-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/border-width-interpolation.html
index 1826c0c..bf5f89c5 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/border-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/border-width-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'border-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/bottom-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/bottom-interpolation.html
index e551d43a..92881cb 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/bottom-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/bottom-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'bottom',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation-expected.txt
index c8209e17..80f105f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (-0.3) is [rgb(0, 0, 0) 7px 33px 7px 33px] 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0) is [rgb(0, 0, 0) 10px 30px 10px 30px] 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0.3) is [rgb(0, 0, 0) 13px 27px 13px 27px] 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0.6) is [rgb(0, 0, 0) 16px 24px 16px 24px] 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (1) is [rgb(0, 0, 0) 20px 20px 20px 20px] 
-PASS CSS Transitions: property <box-shadow> from [] to [20px 20px 20px 20px black] at (1.5) is [rgb(0, 0, 0) 25px 15px 25px 15px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (-0.3) is [rgb(0, 0, 0) 7px 33px 7px 33px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0) is [rgb(0, 0, 0) 10px 30px 10px 30px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.3) is [rgb(0, 0, 0) 13px 27px 13px 27px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.6) is [rgb(0, 0, 0) 16px 24px 16px 24px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1) is [rgb(0, 0, 0) 20px 20px 20px 20px] 
+PASS CSS Transitions: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1.5) is [rgb(0, 0, 0) 25px 15px 25px 15px] 
 PASS CSS Transitions: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px -6px] 
 PASS CSS Transitions: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0) is [none] 
 PASS CSS Transitions: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0.3) is [rgba(0, 0, 0, 0.301961) 6px 6px 6px 6px] 
@@ -61,12 +61,12 @@
 PASS CSS Transitions: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (0.6) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
 PASS CSS Transitions: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (1) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
 PASS CSS Transitions: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (1.5) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (-0.3) is [rgb(0, 0, 0) 7px 33px 7px 33px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0) is [rgb(0, 0, 0) 10px 30px 10px 30px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0.3) is [rgb(0, 0, 0) 13px 27px 13px 27px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (0.6) is [rgb(0, 0, 0) 16px 24px 16px 24px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (1) is [rgb(0, 0, 0) 20px 20px 20px 20px] 
-PASS CSS Animations: property <box-shadow> from [] to [20px 20px 20px 20px black] at (1.5) is [rgb(0, 0, 0) 25px 15px 25px 15px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (-0.3) is [rgb(0, 0, 0) 7px 33px 7px 33px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0) is [rgb(0, 0, 0) 10px 30px 10px 30px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.3) is [rgb(0, 0, 0) 13px 27px 13px 27px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.6) is [rgb(0, 0, 0) 16px 24px 16px 24px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1) is [rgb(0, 0, 0) 20px 20px 20px 20px] 
+PASS CSS Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1.5) is [rgb(0, 0, 0) 25px 15px 25px 15px] 
 PASS CSS Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px -6px] 
 PASS CSS Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0) is [none] 
 PASS CSS Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0.3) is [rgba(0, 0, 0, 0.301961) 6px 6px 6px 6px] 
@@ -122,6 +122,12 @@
 PASS CSS Animations: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (0.6) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
 PASS CSS Animations: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (1) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
 PASS CSS Animations: property <box-shadow> from [10px 20px yellow, 5px 10px green] to [inset 5px 10px green, 15px 20px blue] at (1.5) is [rgb(0, 128, 0) 5px 10px 0px 0px inset, rgb(0, 0, 255) 15px 20px 0px 0px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (-0.3) is [rgb(0, 0, 0) 7px 33px 7px 33px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0) is [rgb(0, 0, 0) 10px 30px 10px 30px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.3) is [rgb(0, 0, 0) 13px 27px 13px 27px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (0.6) is [rgb(0, 0, 0) 16px 24px 16px 24px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1) is [rgb(0, 0, 0) 20px 20px 20px 20px] 
+PASS Web Animations: property <box-shadow> from neutral to [20px 20px 20px 20px black] at (1.5) is [rgb(0, 0, 0) 25px 15px 25px 15px] 
 PASS Web Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px -6px] 
 PASS Web Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0) is [none] 
 PASS Web Animations: property <box-shadow> from [initial] to [20px 20px 20px 20px black] at (0.3) is [rgba(0, 0, 0, 0.301961) 6px 6px 6px 6px] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation.html
index 1658d25..5e5f772c 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/box-shadow-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'box-shadow',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px 20px 20px black',
 }, [
   {at: -0.3, is: '7px 33px 7px 33px black'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/clip-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/clip-interpolation.html
index 48709b7..9f178f4 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/clip-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/clip-interpolation.html
@@ -30,7 +30,7 @@
 <script>
 assertInterpolation({
   property: 'clip',
-  from: '',
+  from: neutralKeyframe,
   to: 'rect(20px, 20px, 20px, 20px)',
 }, [
   {at: -1, is: 'rect(-20px 180px -20px 180px)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/color-interpolation.html
index c8a86c1..55e15e52 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/color-interpolation.html
@@ -19,7 +19,7 @@
 <script>
 assertInterpolation({
   property: 'color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -0.3, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation-expected.txt
index 0bbae085..eff0c38 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
-PASS CSS Transitions: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
+PASS CSS Transitions: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(-10deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(6deg)] 
@@ -43,14 +43,20 @@
 PASS CSS Transitions: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (0.6) is [blur(10px)] 
 PASS CSS Transitions: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Transitions: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1.5) is [blur(10px)] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (-0.5) is [opacity(1) hue-rotate(-90deg)] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0) is [none] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.25) is [opacity(0.875) hue-rotate(45deg)] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.5) is [opacity(0.75) hue-rotate(90deg)] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1) is [opacity(0.5) hue-rotate(180deg)] 
+PASS CSS Transitions: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1.5) is [opacity(0.25) hue-rotate(270deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (-0.5) is [blur(4px) hue-rotate(-90deg)] 
-FAIL CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] assert_equals: expected "blur ( 6px ) hue - rotate ( 0deg ) " but got "blur ( 6px ) "
+PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] 
 PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.25) is [blur(7px) hue-rotate(45deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.5) is [blur(8px) hue-rotate(90deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1) is [blur(10px) hue-rotate(180deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1.5) is [blur(12px) hue-rotate(270deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (-0.5) is [hue-rotate(-90deg)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0.25) is [hue-rotate(45deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0.5) is [hue-rotate(90deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (1) is [hue-rotate(180deg)] 
@@ -59,26 +65,26 @@
 PASS CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0) is [hue-rotate(180deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0.25) is [hue-rotate(135deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0.5) is [hue-rotate(90deg)] 
-FAIL CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1.5) is [hue-rotate(-90deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (-1) is [blur(0px)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (0) is [none] assert_equals: expected "blur ( 0px ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (0.5) is [blur(5px)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [blur(10px)] at (1.5) is [blur(15px)] 
 PASS CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (-1) is [brightness(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (0) is [brightness(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (0.5) is [brightness(0.5)] 
-FAIL CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (1) is [none] assert_equals: expected "brightness ( 1 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [brightness(0)] to [none] at (1.5) is [brightness(1.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (-1) is [contrast(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (0) is [contrast(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (0.5) is [contrast(0.5)] 
-FAIL CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (1) is [none] assert_equals: expected "contrast ( 1 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [contrast(0)] to [none] at (1.5) is [contrast(1.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgba(0, 0, 0, 0) -20px -10px 0px)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0) is [none] 
-PASS CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] 
+FAIL CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] assert_equals: expected "drop - shadow ( rgba ( 0 , 128 , 0 , 0.5 ) 10px 5px 0px ) " but got "drop - shadow ( rgba ( 0 , 127 , 0 , 0.5 ) 10px 5px 0px ) "
 PASS CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 192, 0) 30px 15px 0px)] 
 PASS CSS Transitions: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgb(255, 255, 255) -20px -10px 0px)] 
@@ -87,32 +93,32 @@
 PASS CSS Transitions: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Transitions: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 65, 0) 30px 15px 0px)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (-1) is [grayscale(0)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (0) is [none] assert_equals: expected "grayscale ( 0 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (0.5) is [grayscale(0.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (1) is [grayscale(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [grayscale(1)] at (1.5) is [grayscale(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (-1) is [hue-rotate(-360deg)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0.5) is [hue-rotate(180deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (1) is [hue-rotate(360deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (1.5) is [hue-rotate(540deg)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (-1) is [invert(0)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (0) is [none] assert_equals: expected "invert ( 0 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (0.5) is [invert(0.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (1) is [invert(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [invert(1)] at (1.5) is [invert(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (-1) is [opacity(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (0) is [opacity(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (0.5) is [opacity(0.5)] 
-FAIL CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (1) is [none] assert_equals: expected "opacity ( 1 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [opacity(0)] to [none] at (1.5) is [opacity(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (-1) is [saturate(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (0) is [saturate(0)] 
 PASS CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (0.5) is [saturate(0.5)] 
-FAIL CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (1) is [none] assert_equals: expected "saturate ( 1 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (1) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [saturate(0)] to [none] at (1.5) is [saturate(1.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (-1) is [sepia(0)] 
-FAIL CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (0) is [none] assert_equals: expected "sepia ( 0 ) " but got "none "
+PASS CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (0) is [none] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [none] to [sepia(1)] at (1.5) is [sepia(1)] 
@@ -135,12 +141,12 @@
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Transitions: property <-webkit-filter> from [initial] to [sepia(1)] at (1.5) is [sepia(1)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
-PASS CSS Animations: property <-webkit-filter> from [] to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(5deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0) is [hue-rotate(10deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0.3) is [hue-rotate(13deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (0.6) is [hue-rotate(16deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (1) is [hue-rotate(20deg)] 
+PASS CSS Animations: property <-webkit-filter> from neutral to [hue-rotate(20deg)] at (1.5) is [hue-rotate(25deg)] 
 PASS CSS Animations: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (-0.5) is [hue-rotate(-10deg)] 
 PASS CSS Animations: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [initial] to [hue-rotate(20deg)] at (0.3) is [hue-rotate(6deg)] 
@@ -178,14 +184,20 @@
 PASS CSS Animations: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (0.6) is [blur(10px)] 
 PASS CSS Animations: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Animations: property <-webkit-filter> from [grayscale(0) blur(0px)] to [blur(10px)] at (1.5) is [blur(10px)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (-0.5) is [opacity(1) hue-rotate(-90deg)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0) is [none] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.25) is [opacity(0.875) hue-rotate(45deg)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (0.5) is [opacity(0.75) hue-rotate(90deg)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1) is [opacity(0.5) hue-rotate(180deg)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [opacity(0.5) hue-rotate(180deg)] at (1.5) is [opacity(0.25) hue-rotate(270deg)] 
 PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (-0.5) is [blur(4px) hue-rotate(-90deg)] 
-FAIL CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] assert_equals: expected "blur ( 6px ) hue - rotate ( 0deg ) " but got "blur ( 6px ) "
+PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0) is [blur(6px)] 
 PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.25) is [blur(7px) hue-rotate(45deg)] 
 PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (0.5) is [blur(8px) hue-rotate(90deg)] 
 PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1) is [blur(10px) hue-rotate(180deg)] 
 PASS CSS Animations: property <-webkit-filter> from [blur(6px)] to [blur(10px) hue-rotate(180deg)] at (1.5) is [blur(12px) hue-rotate(270deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (-0.5) is [hue-rotate(-90deg)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0.25) is [hue-rotate(45deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (0.5) is [hue-rotate(90deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(180deg)] at (1) is [hue-rotate(180deg)] 
@@ -194,26 +206,26 @@
 PASS CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0) is [hue-rotate(180deg)] 
 PASS CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0.25) is [hue-rotate(135deg)] 
 PASS CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (0.5) is [hue-rotate(90deg)] 
-FAIL CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [hue-rotate(180deg)] to [none] at (1.5) is [hue-rotate(-90deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (-1) is [blur(0px)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (0) is [none] assert_equals: expected "blur ( 0px ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (0.5) is [blur(5px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (1) is [blur(10px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [blur(10px)] at (1.5) is [blur(15px)] 
 PASS CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (-1) is [brightness(0)] 
 PASS CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (0) is [brightness(0)] 
 PASS CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (0.5) is [brightness(0.5)] 
-FAIL CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (1) is [none] assert_equals: expected "brightness ( 1 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [brightness(0)] to [none] at (1.5) is [brightness(1.5)] 
 PASS CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (-1) is [contrast(0)] 
 PASS CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (0) is [contrast(0)] 
 PASS CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (0.5) is [contrast(0.5)] 
-FAIL CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (1) is [none] assert_equals: expected "contrast ( 1 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [contrast(0)] to [none] at (1.5) is [contrast(1.5)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgba(0, 0, 0, 0) -20px -10px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0) is [none] 
-PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 127, 0, 0.501961) 10px 5px 0px)] 
+PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (0.5) is [drop-shadow(rgba(0, 128, 0, 0.501961) 10px 5px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 192, 0) 30px 15px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (-1) is [drop-shadow(rgb(255, 255, 255) -20px -10px 0px)] 
@@ -222,32 +234,32 @@
 PASS CSS Animations: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1) is [drop-shadow(rgb(0, 128, 0) 20px 10px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [drop-shadow(0px 0px 0px currentcolor)] to [drop-shadow(20px 10px green)] at (1.5) is [drop-shadow(rgb(0, 65, 0) 30px 15px 0px)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (-1) is [grayscale(0)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (0) is [none] assert_equals: expected "grayscale ( 0 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (0.5) is [grayscale(0.5)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (1) is [grayscale(1)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [grayscale(1)] at (1.5) is [grayscale(1)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (-1) is [hue-rotate(-360deg)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] assert_equals: expected "hue - rotate ( 0deg ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (0.5) is [hue-rotate(180deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (1) is [hue-rotate(360deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [hue-rotate(360deg)] at (1.5) is [hue-rotate(540deg)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (-1) is [invert(0)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (0) is [none] assert_equals: expected "invert ( 0 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (0.5) is [invert(0.5)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (1) is [invert(1)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [invert(1)] at (1.5) is [invert(1)] 
 PASS CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (-1) is [opacity(0)] 
 PASS CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (0) is [opacity(0)] 
 PASS CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (0.5) is [opacity(0.5)] 
-FAIL CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (1) is [none] assert_equals: expected "opacity ( 1 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [opacity(0)] to [none] at (1.5) is [opacity(1)] 
 PASS CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (-1) is [saturate(0)] 
 PASS CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (0) is [saturate(0)] 
 PASS CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (0.5) is [saturate(0.5)] 
-FAIL CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (1) is [none] assert_equals: expected "saturate ( 1 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (1) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [saturate(0)] to [none] at (1.5) is [saturate(1.5)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (-1) is [sepia(0)] 
-FAIL CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (0) is [none] assert_equals: expected "sepia ( 0 ) " but got "none "
+PASS CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (0.5) is [sepia(0.5)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (1) is [sepia(1)] 
 PASS CSS Animations: property <-webkit-filter> from [none] to [sepia(1)] at (1.5) is [sepia(1)] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation.html
index 31ea5f4b4..884f89d 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/filter-interpolation.html
@@ -30,7 +30,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-filter',
-  from: '',
+  from: neutralKeyframe,
   to: 'hue-rotate(20deg)',
 }, [
   {at: -0.5, is: 'hue-rotate(5deg)'},
@@ -118,11 +118,24 @@
 // Partially matching lists:
 assertInterpolation({
   property: '-webkit-filter',
+  from: 'none',
+  to: 'opacity(0.5) hue-rotate(180deg)',
+}, [
+  {at: -0.5, is: 'opacity(1) hue-rotate(-90deg)'},
+  {at: 0, is: 'none'},
+  {at: 0.25, is: 'opacity(0.875) hue-rotate(45deg)'},
+  {at: 0.5, is: 'opacity(0.75) hue-rotate(90deg)'},
+  {at: 1, is: 'opacity(0.5) hue-rotate(180deg)'},
+  {at: 1.5, is: 'opacity(0.25) hue-rotate(270deg)'},
+]);
+
+assertInterpolation({
+  property: '-webkit-filter',
   from: 'blur(6px)',
   to: 'blur(10px) hue-rotate(180deg)'
 }, [
   {at: -0.5, is: 'blur(4px) hue-rotate(-90deg)'},
-  {at: 0, is: 'blur(6px) hue-rotate(0deg)'},
+  {at: 0, is: 'blur(6px)'},
   {at: 0.25, is: 'blur(7px) hue-rotate(45deg)'},
   {at: 0.5, is: 'blur(8px) hue-rotate(90deg)'},
   {at: 1, is: 'blur(10px) hue-rotate(180deg)'},
@@ -135,7 +148,7 @@
   to: 'hue-rotate(180deg)'
 }, [
   {at: -0.5, is: 'hue-rotate(-90deg)'},
-  {at: 0, is: 'hue-rotate(0deg)'},
+  {at: 0, is: 'none'},
   {at: 0.25, is: 'hue-rotate(45deg)'},
   {at: 0.5, is: 'hue-rotate(90deg)'},
   {at: 1, is: 'hue-rotate(180deg)'},
@@ -151,7 +164,7 @@
   {at: 0, is: 'hue-rotate(180deg)'},
   {at: 0.25, is: 'hue-rotate(135deg)'},
   {at: 0.5, is: 'hue-rotate(90deg)'},
-  {at: 1, is: 'hue-rotate(0deg)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'hue-rotate(-90deg)'},
 ]);
 
@@ -162,7 +175,7 @@
   to: 'blur(10px)'
 }, [
   {at: -1, is: 'blur(0px)'}, // Negative values are not allowed.
-  {at: 0, is: 'blur(0px)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'blur(5px)'},
   {at: 1, is: 'blur(10px)'},
   {at: 1.5, is: 'blur(15px)'}
@@ -176,7 +189,7 @@
   {at: -1, is: 'brightness(0)'}, // Negative values are not allowed.
   {at: 0, is: 'brightness(0)'},
   {at: 0.5, is: 'brightness(0.5)'},
-  {at: 1, is: 'brightness(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'brightness(1.5)'}
 ]);
 
@@ -188,7 +201,7 @@
   {at: -1, is: 'contrast(0)'}, // Negative values are not allowed.
   {at: 0, is: 'contrast(0)'},
   {at: 0.5, is: 'contrast(0.5)'},
-  {at: 1, is: 'contrast(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'contrast(1.5)'}
 ]);
 
@@ -199,7 +212,7 @@
 }, [
   {at: -1, is: 'drop-shadow(-20px -10px transparent)'},
   {at: 0, is: 'none'},
-  {at: 0.5, is: 'drop-shadow(10px 5px rgba(0, 127, 0, 0.5))'},
+  {at: 0.5, is: 'drop-shadow(10px 5px rgba(0, 128, 0, 0.5))'},
   {at: 1, is: 'drop-shadow(20px 10px green)'},
   {at: 1.5, is: 'drop-shadow(30px 15px #00C000)'}
 ]);
@@ -222,7 +235,7 @@
   to: 'grayscale(1)'
 }, [
   {at: -1, is: 'grayscale(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'grayscale(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'grayscale(0.5)'},
   {at: 1, is: 'grayscale(1)'},
   {at: 1.5, is: 'grayscale(1)'} // Should clamp values to 1.
@@ -234,7 +247,7 @@
   to: 'hue-rotate(360deg)'
 }, [
   {at: -1, is: 'hue-rotate(-360deg)'},
-  {at: 0, is: 'hue-rotate(0deg)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'hue-rotate(180deg)'},
   {at: 1, is: 'hue-rotate(360deg)'},
   {at: 1.5, is: 'hue-rotate(540deg)'}
@@ -246,7 +259,7 @@
   to: 'invert(1)'
 }, [
   {at: -1, is: 'invert(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'invert(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'invert(0.5)'},
   {at: 1, is: 'invert(1)'},
   {at: 1.5, is: 'invert(1)'} // Should clamp values to 1.
@@ -260,7 +273,7 @@
   {at: -1, is: 'opacity(0)'}, // Negative values are not allowed.
   {at: 0, is: 'opacity(0)'},
   {at: 0.5, is: 'opacity(0.5)'},
-  {at: 1, is: 'opacity(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'opacity(1)'} // Should clamp values to 1.
 ]);
 
@@ -272,7 +285,7 @@
   {at: -1, is: 'saturate(0)'}, // Negative values are not allowed.
   {at: 0, is: 'saturate(0)'},
   {at: 0.5, is: 'saturate(0.5)'},
-  {at: 1, is: 'saturate(1)'},
+  {at: 1, is: 'none'},
   {at: 1.5, is: 'saturate(1.5)'}
 ]);
 
@@ -282,7 +295,7 @@
   to: 'sepia(1)'
 }, [
   {at: -1, is: 'sepia(0)'}, // Negative values are not allowed.
-  {at: 0, is: 'sepia(0)'},
+  {at: 0, is: 'none'},
   {at: 0.5, is: 'sepia(0.5)'},
   {at: 1, is: 'sepia(1)'},
   {at: 1.5, is: 'sepia(1)'} // Should clamp values to 1.
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/flex-basis-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/flex-basis-interpolation.html
index 84fedccb3..332c856 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/flex-basis-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/flex-basis-interpolation.html
@@ -13,7 +13,7 @@
 <script>
 assertInterpolation({
   property: 'flex-basis',
-  from: '',
+  from: neutralKeyframe,
   to: '2%',
 }, [
   {at: -0.3, is: '0.7%'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/flex-grow-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/flex-grow-interpolation.html
index d09cd38..0da58e2 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/flex-grow-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/flex-grow-interpolation.html
@@ -29,7 +29,7 @@
 <script>
 assertInterpolation({
   property: 'flex-grow',
-  from: '',
+  from: neutralKeyframe,
   to: '2',
 }, [
   {at: -0.3, is: '0.7'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/flex-shrink-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/flex-shrink-interpolation.html
index fe3a65d6..a5645827 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/flex-shrink-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/flex-shrink-interpolation.html
@@ -13,7 +13,7 @@
 <script>
 assertInterpolation({
   property: 'flex-shrink',
-  from: '',
+  from: neutralKeyframe,
   to: '2',
 }, [
   {at: -0.3, is: '1.35'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/font-size-adjust-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/font-size-adjust-interpolation.html
index f22713a9..30b64b2 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/font-size-adjust-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/font-size-adjust-interpolation.html
@@ -35,7 +35,7 @@
 <script>
 assertInterpolation({
   property: 'font-size-adjust',
-  from: '',
+  from: neutralKeyframe,
   to: '2',
 }, [
   {at: -2, is: '0'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/font-size-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/font-size-interpolation.html
index bc56f45..d194789 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/font-size-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/font-size-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'font-size',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -2, is: '0px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/font-weight-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/font-weight-interpolation.html
index bdf77c6..01252f6b 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/font-weight-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/font-weight-interpolation.html
@@ -65,7 +65,7 @@
 <script>
 assertInterpolation({
   property: 'font-weight',
-  from: '',
+  from: neutralKeyframe,
   to: '900',
 }, [
   {at: -0.3, is: '600'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/height-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/height-interpolation.html
index e11e4b6..317cc18 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/height-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/height-interpolation.html
@@ -21,7 +21,7 @@
 <script>
 assertInterpolation({
   property: 'height',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/left-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/left-interpolation.html
index d3d95c80..e88760e 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/left-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/left-interpolation.html
@@ -21,7 +21,7 @@
 <script>
 assertInterpolation({
   property: 'left',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/left-zoomed-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/left-zoomed-interpolation.html
index 9dbc5b1..357e3ea 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/left-zoomed-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/left-zoomed-interpolation.html
@@ -31,7 +31,7 @@
 
 assertInterpolation({
   property: 'left',
-  from: '',
+  from: neutralKeyframe,
   to: '10px',
   method: 'CSS Animations',
 }, [
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/letter-spacing-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/letter-spacing-interpolation.html
index 94d173d..ac2a7a9 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/letter-spacing-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/letter-spacing-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'letter-spacing',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '33px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/line-height-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/line-height-interpolation.html
index b62cc65..d0087e3 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/line-height-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/line-height-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'line-height',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -1, is: '0px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation-expected.txt
index 4c95dbc..c694c80 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../green-20.png)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.3)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.5)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.6)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (1) is [url(file:///.../stripes-20.png)] 
-PASS CSS Transitions: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (1.5) is [url(file:///.../stripes-20.png)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../green-20.png)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.3)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.5)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.6)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1) is [url(file:///.../stripes-20.png)] 
+PASS CSS Transitions: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1.5) is [url(file:///.../stripes-20.png)] 
 PASS CSS Transitions: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../stripes-20.png)] 
 PASS CSS Transitions: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../stripes-20.png)] 
 PASS CSS Transitions: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0.3) is [url(file:///.../stripes-20.png)] 
@@ -63,13 +63,13 @@
 FAIL CSS Transitions: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (0.6) is [linear-gradient(45deg, blue, orange)] assert_equals: expected "- webkit - cross - fade ( linear - gradient ( - 45deg , red , yellow ) , linear - gradient ( 45deg , blue , orange ) , 0.6 ) " but got "linear - gradient ( 45deg , blue , orange ) "
 PASS CSS Transitions: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1) is [linear-gradient(45deg, blue, orange)] 
 PASS CSS Transitions: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1.5) is [linear-gradient(45deg, blue, orange)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../green-20.png)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.3)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.5)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.6)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (1) is [url(file:///.../stripes-20.png)] 
-PASS CSS Animations: property <list-style-image> from [] to [url(../resources/stripes-20.png)] at (1.5) is [url(file:///.../stripes-20.png)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../green-20.png)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.3)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.5)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.6)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1) is [url(file:///.../stripes-20.png)] 
+PASS CSS Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1.5) is [url(file:///.../stripes-20.png)] 
 PASS CSS Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (-0.3) is [none] 
 PASS CSS Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0) is [none] 
 PASS CSS Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0.3) is [none] 
@@ -126,6 +126,13 @@
 PASS CSS Animations: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (0.6) is [-webkit-cross-fade(linear-gradient(-45deg, red, yellow), linear-gradient(45deg, blue, orange), 0.6)] 
 PASS CSS Animations: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1) is [linear-gradient(45deg, blue, orange)] 
 PASS CSS Animations: property <list-style-image> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1.5) is [linear-gradient(45deg, blue, orange)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0) is [url(file:///.../green-20.png)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.3)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.5)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../green-20.png), url(file:///.../stripes-20.png), 0.6)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1) is [url(file:///.../stripes-20.png)] 
+PASS Web Animations: property <list-style-image> from neutral to [url(../resources/stripes-20.png)] at (1.5) is [url(file:///.../stripes-20.png)] 
 PASS Web Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (-0.3) is [none] 
 PASS Web Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0) is [none] 
 PASS Web Animations: property <list-style-image> from [initial] to [url(../resources/stripes-20.png)] at (0.3) is [none] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation.html
index 373f7996..80d53604 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/list-style-image-interpolation.html
@@ -39,7 +39,7 @@
 }
 
 assertCrossfadeInterpolation({
-  from: '',
+  from: neutralKeyframe,
   fromComputed: 'url(../resources/green-20.png)',
   to: 'url(../resources/stripes-20.png)',
 });
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/margin-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/margin-interpolation.html
index 04228d7..b6cc630 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/margin-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/margin-interpolation.html
@@ -28,7 +28,7 @@
 <script>
 assertInterpolation({
   property: 'margin',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '33px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/max-height-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/max-height-interpolation.html
index 99a5b5e..12a039d1 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/max-height-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/max-height-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'max-height',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.5, is: '5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/max-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/max-width-interpolation.html
index 18d1f7d..9c8ae28 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/max-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/max-width-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'max-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.5, is: '5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/min-height-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/min-height-interpolation.html
index 5eaf66e..c6eedcfe 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/min-height-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/min-height-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'min-height',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.5, is: '5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/min-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/min-width-interpolation.html
index 110c2c4c..0711cd1 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/min-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/min-width-interpolation.html
@@ -19,7 +19,7 @@
 <script>
 assertInterpolation({
   property: 'min-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.5, is: '5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/motion-offset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/motion-offset-interpolation.html
index 623ed86..58b1eb5 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/motion-offset-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/motion-offset-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'motion-offset',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/motion-rotation-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/motion-rotation-interpolation.html
index aafe41f..b670c1ac 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/motion-rotation-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/motion-rotation-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'motion-rotation',
-  from: '',
+  from: neutralKeyframe,
   to: '20deg',
 }, [
   {at: -0.3, is: '7deg'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/object-position-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/object-position-interpolation.html
index bd214386..320e171 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/object-position-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/object-position-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'object-position',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px',
 }, [
   {at: -0.3, is: '7px 33px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/opacity-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/opacity-interpolation.html
index c990b84..ceef704 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/opacity-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/opacity-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'opacity',
-  from: '',
+  from: neutralKeyframe,
   to: '0.2',
 }, [
   {at: -0.3, is: '0.07'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/orphans-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/orphans-interpolation.html
index daf3b867..99004e7 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/orphans-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/orphans-interpolation.html
@@ -12,7 +12,7 @@
 <script>
 assertInterpolation({
   property: 'orphans',
-  from: '',
+  from: neutralKeyframe,
   to: '20',
 }, [
   {at: -0.5, is: '5'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/outline-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/outline-color-interpolation.html
index 2505fb0..a7873a4 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/outline-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/outline-color-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'outline-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -0.3, is: 'rgb(0, 0, 255)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/outline-offset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/outline-offset-interpolation.html
index 98a1e986..bc96f7d9 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/outline-offset-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/outline-offset-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'outline-offset',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/outline-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/outline-width-interpolation.html
index 04a25be..ce201df 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/outline-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/outline-width-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'outline-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/padding-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/padding-interpolation.html
index c4753f6..70d5c54 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/padding-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/padding-interpolation.html
@@ -21,7 +21,7 @@
 <script>
 assertInterpolation({
   property: 'padding',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/perspective-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/perspective-interpolation.html
index c9dd607..53ec74ed 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/perspective-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/perspective-interpolation.html
@@ -33,7 +33,7 @@
 <script>
 assertInterpolation({
   property: 'perspective',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -20, is: 'none'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/perspective-origin-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/perspective-origin-interpolation.html
index d2a10de..b2bcffd 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/perspective-origin-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/perspective-origin-interpolation.html
@@ -35,7 +35,7 @@
 <script>
 assertInterpolation({
   property: 'perspective-origin',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px',
 }, [
   {at: -0.3, is: '7px 33px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/position-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/position-interpolation.html
index 8ba88c5..29aa76a9 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/position-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/position-interpolation.html
@@ -34,7 +34,7 @@
 
 assertInterpolation({
   property: 'position',
-  from: '',
+  from: neutralKeyframe,
   to: 'absolute',
   method: 'CSS Animations',
 }, [
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js b/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
index 4543094..aae95be 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/resources/interpolation-test.js
@@ -50,6 +50,10 @@
  *        Exactly one of (addTo, replaceTo) must be specified.
  *  - afterTest(callback)
  *        Calls callback after all the tests have executed.
+ *
+ * The following object is exported:
+ *  - neutralKeyframe
+ *        Can be used as the from/to value to use a neutral keyframe.
  */
 'use strict';
 (function() {
@@ -62,6 +66,10 @@
   var webAnimationsEnabled = typeof Element.prototype.animate === 'function';
   var expectNoInterpolation = {};
   var afterTestHook = function() {};
+  var neutralKeyframe = {};
+  function isNeutralKeyframe(keyframe) {
+    return keyframe === neutralKeyframe;
+  }
 
   var cssAnimationsInterpolation = {
     name: 'CSS Animations',
@@ -78,8 +86,8 @@
       }
       cssAnimationsData.sharedStyle.textContent += '' +
         '@keyframes animation' + id + ' {' +
-          'from {' + property + ': ' + from + ';}' +
-          'to {' + property + ': ' + to + ';}' +
+          (isNeutralKeyframe(from) ? '' : `from {${property}: ${from};}`) +
+          (isNeutralKeyframe(to) ? '' : `to {${property}: ${to};}`) +
         '}';
       target.style.animationName = 'animation' + id;
       target.style.animationDuration = '2e10s';
@@ -94,7 +102,7 @@
     supportsProperty: function() {return true;},
     supportsValue: function() {return true;},
     setup: function(property, from, target) {
-      target.style[property] = from;
+      target.style[property] = isNeutralKeyframe(from) ? '' : from;
     },
     nonInterpolationExpectations: function(from, to) {
       return expectFlip(from, to, -Infinity);
@@ -104,7 +112,7 @@
       target.style.transitionDelay = '-1e10s';
       target.style.transitionTimingFunction = createEasing(at);
       target.style.transitionProperty = property;
-      target.style[property] = to;
+      target.style[property] = isNeutralKeyframe(to) ? '' : to;
     },
     rebaseline: false,
   };
@@ -118,18 +126,30 @@
       return expectFlip(from, to, 0.5);
     },
     interpolate: function(property, from, to, at, target) {
+      this.interpolateComposite(property, from, 'replace', to, 'replace', at, target);
+    },
+    interpolateComposite: function(property, from, fromComposite, to, toComposite, at, target) {
       // Convert to camelCase
       for (var i = property.length - 2; i > 0; --i) {
         if (property[i] === '-') {
           property = property.substring(0, i) + property[i + 1].toUpperCase() + property.substring(i + 2);
         }
       }
-      this.interpolateKeyframes([
-        {offset: 0, [property]: from},
-        {offset: 1, [property]: to},
-      ], at, target);
-    },
-    interpolateKeyframes: function(keyframes, at, target) {
+      var keyframes = [];
+      if (!isNeutralKeyframe(from)) {
+        keyframes.push({
+          offset: 0,
+          composite: fromComposite,
+          [property]: from,
+        });
+      }
+      if (!isNeutralKeyframe(to)) {
+        keyframes.push({
+          offset: 1,
+          composite: toComposite,
+          [property]: to,
+        });
+      }
       target.animate(keyframes, {
         fill: 'forwards',
         duration: 1,
@@ -258,6 +278,14 @@
     compositionTests.push({options, expectations});
   }
 
+  function keyframeText(keyframe) {
+    return isNeutralKeyframe(keyframe) ? 'neutral' : `[${keyframe}]`;
+  }
+
+  function keyframeCode(keyframe) {
+    return isNeutralKeyframe(keyframe) ? 'neutralKeyframe' : `'${keyframe}'`;
+  }
+
   function createInterpolationTestTargets(interpolationMethod, interpolationMethodContainer, interpolationTest, rebaselineContainer) {
     var property = interpolationTest.options.property;
     var from = interpolationTest.options.from;
@@ -273,14 +301,14 @@
       rebaseline.appendChild(document.createTextNode(`\
 assertInterpolation({
   property: '${property}',
-  from: '${from}',
-  to: '${to}',
+  from: ${keyframeCode(from)},
+  to: ${keyframeCode(to)},
 }, [\n`));
       var rebaselineExpectation;
       rebaseline.appendChild(rebaselineExpectation = document.createTextNode(''));
       rebaseline.appendChild(document.createTextNode(']);\n\n'));
     }
-    var testText = `${interpolationMethod.name}: property <${property}> from [${from}] to [${to}]`;
+    var testText = `${interpolationMethod.name}: property <${property}> from ${keyframeText(from)} to ${keyframeText(to)}`;
     var testContainer = createElement(interpolationMethodContainer, 'div', testText);
     createElement(testContainer, 'br');
     var expectations = interpolationTest.expectations;
@@ -344,15 +372,7 @@
       var target = actualTargetContainer.target;
       target.style[property] = underlying;
       target.interpolate = function() {
-        webAnimationsInterpolation.interpolateKeyframes([{
-          offset: 0,
-          composite: fromComposite,
-          [toCamelCase(property)]: from,
-        }, {
-          offset: 1,
-          composite: toComposite,
-          [toCamelCase(property)]: to,
-        }], expectation.at, target);
+        webAnimationsInterpolation.interpolateComposite(property, from, fromComposite, to, toComposite, expectation.at, target);
       };
       target.measure = function() {
         var actualValue = getComputedStyle(target)[property];
@@ -413,11 +433,6 @@
     afterTestHook = f;
   }
 
-  window.assertInterpolation = assertInterpolation;
-  window.assertNoInterpolation = assertNoInterpolation;
-  window.assertComposition = assertComposition;
-  window.afterTest = afterTest;
-
   loadScript('../../resources/testharness.js').then(function() {
     return loadScript('../../resources/testharnessreport.js');
   }).then(function() {
@@ -427,4 +442,10 @@
       asyncHandle.done()
     });
   });
+
+  window.assertInterpolation = assertInterpolation;
+  window.assertNoInterpolation = assertNoInterpolation;
+  window.assertComposition = assertComposition;
+  window.afterTest = afterTest;
+  window.neutralKeyframe = neutralKeyframe;
 })();
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/right-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/right-interpolation.html
index 4968fab..8f5e8da4 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/right-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/right-interpolation.html
@@ -21,7 +21,7 @@
 <script>
 assertInterpolation({
   property: 'right',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html
index c8c36451..6825837 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/rotate-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'rotate',
-  from: '',
+  from: neutralKeyframe,
   to: '30deg',
 }, [
   {at: -1, is: '-10deg'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/scale-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/scale-interpolation.html
index 41344b5..d5f0894 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/scale-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/scale-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'scale',
-  from: '',
+  from: neutralKeyframe,
   to: '1.5',
 }, [
   {at: -1, is: '0.7 0.7'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/shape-image-threshold-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/shape-image-threshold-interpolation.html
index da47b9f..2f12343 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/shape-image-threshold-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/shape-image-threshold-interpolation.html
@@ -13,7 +13,7 @@
 <script>
 assertInterpolation({
   property: 'shape-image-threshold',
-  from: '',
+  from: neutralKeyframe,
   to: '0.8',
 }, [
   {at: -1.5, is: '0.3'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/shape-margin-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/shape-margin-interpolation.html
index bb8e756..6bf3562 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/shape-margin-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/shape-margin-interpolation.html
@@ -13,7 +13,7 @@
 <script>
 assertInterpolation({
   property: 'shape-margin',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/shape-outside-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/shape-outside-interpolation.html
index fe52428..1e28397 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/shape-outside-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/shape-outside-interpolation.html
@@ -15,7 +15,7 @@
 
 assertInterpolation({
   property: 'shape-outside',
-  from: '',
+  from: neutralKeyframe,
   to: 'circle(40% at 20% 20%)',
 }, [
   {at: -0.3, is: 'circle(66% at 7% 33%)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-baseline-shift-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-baseline-shift-interpolation.html
index 71a22c4..ae384500 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-baseline-shift-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-baseline-shift-interpolation.html
@@ -38,7 +38,7 @@
 <script>
 assertInterpolation({
   property: 'baseline-shift',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.25, is: '-5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-cx-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-cx-interpolation.html
index 27941552..0f47920 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-cx-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-cx-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'cx',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.25, is: '57.5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-cy-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-cy-interpolation.html
index 83c06f7..a2c8e90a 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-cy-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-cy-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'cy',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.25, is: '57.5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-interpolation.html
index 10d547a..8f89b6a 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-interpolation.html
@@ -34,7 +34,7 @@
 <script>
 assertInterpolation({
   property: 'fill',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-opacity-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-opacity-interpolation.html
index 65a4739a..e578f0d 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-opacity-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-fill-opacity-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'fill-opacity',
-  from: '',
+  from: neutralKeyframe,
   to: '0.4',
 }, [
   {at: -0.3, is: '0.66'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-color-interpolation.html
index 0533c7f..5c989dd8 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-color-interpolation.html
@@ -30,7 +30,7 @@
 <script>
 assertInterpolation({
   property: 'flood-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-opacity-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-opacity-interpolation.html
index ed96ec4..50abbea 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-opacity-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-flood-opacity-interpolation.html
@@ -33,7 +33,7 @@
 <script>
 assertInterpolation({
   property: 'flood-opacity',
-  from: '',
+  from: neutralKeyframe,
   to: '0.4',
 }, [
   {at: -1, is: '0.8'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-lighting-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-lighting-color-interpolation.html
index ec946af..fb7d1fc 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-lighting-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-lighting-color-interpolation.html
@@ -33,7 +33,7 @@
 <script>
 assertInterpolation({
   property: 'lighting-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-r-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-r-interpolation.html
index 668b6d9e..7e3b7fe 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-r-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-r-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'r',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-rx-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-rx-interpolation.html
index 0da9c0ea..a481e62 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-rx-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-rx-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'rx',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-ry-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-ry-interpolation.html
index 4cf9e89e..791424ed 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-ry-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-ry-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'ry',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-color-interpolation.html
index 611f0fe..6f370eb 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-color-interpolation.html
@@ -29,7 +29,7 @@
 <script>
 assertInterpolation({
   property: 'stop-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-opacity-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-opacity-interpolation.html
index 15f9c7b9..c04579a 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-opacity-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stop-opacity-interpolation.html
@@ -27,7 +27,7 @@
 <script>
 assertInterpolation({
   property: 'stop-opacity',
-  from: '',
+  from: neutralKeyframe,
   to: '0.4',
 }, [
   {at: -0.4, is: '0.68'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
index a44aa91..7024471f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation-expected.txt
@@ -1,15 +1,15 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (-0.6) is [4px, 36px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (-0.4) is [6px, 34px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (-0.2) is [8px, 32px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (0) is [10px, 30px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (0.2) is [12px, 28px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (0.4) is [14px, 26px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (0.6) is [16px, 24px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (0.8) is [18px, 22px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (1) is [20px, 20px] 
-PASS CSS Transitions: property <stroke-dasharray> from [] to [20 20] at (1.2) is [22px, 18px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (-0.6) is [4px, 36px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (-0.4) is [6px, 34px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (-0.2) is [8px, 32px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (0) is [10px, 30px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (0.2) is [12px, 28px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (0.4) is [14px, 26px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (0.6) is [16px, 24px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (0.8) is [18px, 22px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (1) is [20px, 20px] 
+PASS CSS Transitions: property <stroke-dasharray> from neutral to [20 20] at (1.2) is [22px, 18px] 
 FAIL CSS Transitions: property <stroke-dasharray> from [initial] to [20 20] at (-0.3) is [0px, 0px] assert_equals: expected "20px , 20px " but got "0px , 0px "
 FAIL CSS Transitions: property <stroke-dasharray> from [initial] to [20 20] at (0) is [none] assert_equals: expected "20px , 20px " but got "none "
 FAIL CSS Transitions: property <stroke-dasharray> from [initial] to [20 20] at (0.3) is [6px, 6px] assert_equals: expected "20px , 20px " but got "6px , 6px "
@@ -155,16 +155,16 @@
 PASS CSS Transitions: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (0.8) is [1312px, 164px, 3936px, 328px, 1440px, 172px, 3872px, 324px, 1376px, 168px, 4000px, 332px] 
 PASS CSS Transitions: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (1) is [1600px, 200px, 4800px, 400px] 
 PASS CSS Transitions: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (1.2) is [1888px, 236px, 5664px, 472px, 1760px, 228px, 5728px, 476px, 1824px, 232px, 5600px, 468px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (-0.6) is [4px, 36px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (-0.4) is [6px, 34px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (-0.2) is [8px, 32px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (0) is [10px, 30px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (0.2) is [12px, 28px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (0.4) is [14px, 26px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (0.6) is [16px, 24px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (0.8) is [18px, 22px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (1) is [20px, 20px] 
-PASS CSS Animations: property <stroke-dasharray> from [] to [20 20] at (1.2) is [22px, 18px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.6) is [4px, 36px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.4) is [6px, 34px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.2) is [8px, 32px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (0) is [10px, 30px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (0.2) is [12px, 28px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (0.4) is [14px, 26px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (0.6) is [16px, 24px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (0.8) is [18px, 22px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (1) is [20px, 20px] 
+PASS CSS Animations: property <stroke-dasharray> from neutral to [20 20] at (1.2) is [22px, 18px] 
 PASS CSS Animations: property <stroke-dasharray> from [initial] to [20 20] at (-0.3) is [none] 
 PASS CSS Animations: property <stroke-dasharray> from [initial] to [20 20] at (0) is [none] 
 PASS CSS Animations: property <stroke-dasharray> from [initial] to [20 20] at (0.3) is [none] 
@@ -310,6 +310,16 @@
 PASS CSS Animations: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (0.8) is [1312px, 164px, 3936px, 328px, 1440px, 172px, 3872px, 324px, 1376px, 168px, 4000px, 332px] 
 PASS CSS Animations: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (1) is [1600px, 200px, 4800px, 400px] 
 PASS CSS Animations: property <stroke-dasharray> from [10em 20px 30em 40px 50em 60px] to [100em 200px 300em 400px] at (1.2) is [1888px, 236px, 5664px, 472px, 1760px, 228px, 5728px, 476px, 1824px, 232px, 5600px, 468px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.6) is [4px, 36px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.4) is [6px, 34px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (-0.2) is [8px, 32px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (0) is [10px, 30px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (0.2) is [12px, 28px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (0.4) is [14px, 26px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (0.6) is [16px, 24px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (0.8) is [18px, 22px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (1) is [20px, 20px] 
+PASS Web Animations: property <stroke-dasharray> from neutral to [20 20] at (1.2) is [22px, 18px] 
 PASS Web Animations: property <stroke-dasharray> from [initial] to [20 20] at (-0.3) is [none] 
 PASS Web Animations: property <stroke-dasharray> from [initial] to [20 20] at (0) is [none] 
 PASS Web Animations: property <stroke-dasharray> from [initial] to [20 20] at (0.3) is [none] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
index cd485bc..c063c61 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dasharray-interpolation.html
@@ -27,7 +27,7 @@
 <script>
 assertInterpolation({
   property: 'stroke-dasharray',
-  from: '',
+  from: neutralKeyframe,
   to: '20 20',
 }, [
   {at: -0.6, is: '4px, 36px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dashoffset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dashoffset-interpolation.html
index 0116985..24ddba6a 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dashoffset-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-dashoffset-interpolation.html
@@ -27,7 +27,7 @@
 <script>
 assertInterpolation({
   property: 'stroke-dashoffset',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.25, is: '15px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-interpolation.html
index 9305a54..aebc530 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-interpolation.html
@@ -33,7 +33,7 @@
 <script>
 assertInterpolation({
   property: 'stroke',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -0.4, is: 'rgb(255, 180, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-miterlimit-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-miterlimit-interpolation.html
index 3405ec6..7b9316b0f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-miterlimit-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-miterlimit-interpolation.html
@@ -30,7 +30,7 @@
 <script>
 assertInterpolation({
   property: 'stroke-miterlimit',
-  from: '',
+  from: neutralKeyframe,
   to: '2',
 }, [
   {at: -0.4, is: '1.3'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-opacity-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-opacity-interpolation.html
index 8e68b0e..caef5a5d 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-opacity-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-opacity-interpolation.html
@@ -26,7 +26,7 @@
 <script>
 assertInterpolation({
   property: 'stroke-opacity',
-  from: '',
+  from: neutralKeyframe,
   to: '0.4',
 }, [
   {at: -0.3, is: '0.66'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-width-interpolation.html
index 4e87867..e0200c0 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/svg-stroke-width-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'stroke-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/text-decoration-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/text-decoration-color-interpolation.html
index 52359e7..e4802ef 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/text-decoration-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/text-decoration-color-interpolation.html
@@ -27,7 +27,7 @@
 <script>
 assertInterpolation({
   property: 'text-decoration-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation-expected.txt
index a456cfee..55038f1 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (-0.3) is [1px] 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (0) is [10px] 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (0.3) is [19px] 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (0.6) is [28px] 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (1) is [40px] 
-PASS CSS Transitions: property <text-indent> from [] to [40px] at (1.5) is [55px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (-0.3) is [1px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (0) is [10px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (0.3) is [19px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (0.6) is [28px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (1) is [40px] 
+PASS CSS Transitions: property <text-indent> from neutral to [40px] at (1.5) is [55px] 
 PASS CSS Transitions: property <text-indent> from [initial] to [20px] at (-0.3) is [-6px] 
 PASS CSS Transitions: property <text-indent> from [initial] to [20px] at (0) is [0px] 
 PASS CSS Transitions: property <text-indent> from [initial] to [20px] at (0.3) is [6px] 
@@ -56,12 +56,12 @@
 FAIL CSS Transitions: property <text-indent> from [0px] to [50px each-line hanging] at (0.6) is [30px each-line hanging] assert_equals: expected "50px each - line hanging " but got "30px each - line hanging "
 PASS CSS Transitions: property <text-indent> from [0px] to [50px each-line hanging] at (1) is [50px each-line hanging] 
 FAIL CSS Transitions: property <text-indent> from [0px] to [50px each-line hanging] at (1.5) is [75px each-line hanging] assert_equals: expected "50px each - line hanging " but got "75px each - line hanging "
-PASS CSS Animations: property <text-indent> from [] to [40px] at (-0.3) is [1px] 
-PASS CSS Animations: property <text-indent> from [] to [40px] at (0) is [10px] 
-PASS CSS Animations: property <text-indent> from [] to [40px] at (0.3) is [19px] 
-PASS CSS Animations: property <text-indent> from [] to [40px] at (0.6) is [28px] 
-PASS CSS Animations: property <text-indent> from [] to [40px] at (1) is [40px] 
-PASS CSS Animations: property <text-indent> from [] to [40px] at (1.5) is [55px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (-0.3) is [1px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (0) is [10px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (0.3) is [19px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (0.6) is [28px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (1) is [40px] 
+PASS CSS Animations: property <text-indent> from neutral to [40px] at (1.5) is [55px] 
 PASS CSS Animations: property <text-indent> from [initial] to [20px] at (-0.3) is [-6px] 
 PASS CSS Animations: property <text-indent> from [initial] to [20px] at (0) is [0px] 
 PASS CSS Animations: property <text-indent> from [initial] to [20px] at (0.3) is [6px] 
@@ -112,6 +112,12 @@
 PASS CSS Animations: property <text-indent> from [0px] to [50px each-line hanging] at (0.6) is [50px each-line hanging] 
 PASS CSS Animations: property <text-indent> from [0px] to [50px each-line hanging] at (1) is [50px each-line hanging] 
 PASS CSS Animations: property <text-indent> from [0px] to [50px each-line hanging] at (1.5) is [50px each-line hanging] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (-0.3) is [1px] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (0) is [10px] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (0.3) is [19px] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (0.6) is [28px] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (1) is [40px] 
+PASS Web Animations: property <text-indent> from neutral to [40px] at (1.5) is [55px] 
 PASS Web Animations: property <text-indent> from [initial] to [20px] at (-0.3) is [-6px] 
 PASS Web Animations: property <text-indent> from [initial] to [20px] at (0) is [0px] 
 PASS Web Animations: property <text-indent> from [initial] to [20px] at (0.3) is [6px] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation.html
index 39752fd3..a1508194f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/text-indent-interpolation.html
@@ -19,7 +19,7 @@
 <script>
 assertInterpolation({
   property: 'text-indent',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.3, is: '1px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation-expected.txt
index 293aeac..5277838 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (-0.3) is [rgb(255, 176, 0) 7px 33px 7px] 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (0) is [rgb(255, 165, 0) 10px 30px 10px] 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (0.3) is [rgb(179, 154, 0) 13px 27px 13px] 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (0.6) is [rgb(102, 143, 0) 16px 24px 16px] 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (1) is [rgb(0, 128, 0) 20px 20px 20px] 
-PASS CSS Transitions: property <text-shadow> from [] to [20px 20px 20px green] at (1.5) is [rgb(0, 110, 0) 25px 15px 25px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (-0.3) is [rgb(255, 176, 0) 7px 33px 7px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (0) is [rgb(255, 165, 0) 10px 30px 10px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (0.3) is [rgb(179, 154, 0) 13px 27px 13px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (0.6) is [rgb(102, 143, 0) 16px 24px 16px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (1) is [rgb(0, 128, 0) 20px 20px 20px] 
+PASS CSS Transitions: property <text-shadow> from neutral to [20px 20px 20px green] at (1.5) is [rgb(0, 110, 0) 25px 15px 25px] 
 PASS CSS Transitions: property <text-shadow> from [initial] to [20px 20px 20px green] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px] 
 PASS CSS Transitions: property <text-shadow> from [initial] to [20px 20px 20px green] at (0) is [none] 
 FAIL CSS Transitions: property <text-shadow> from [initial] to [20px 20px 20px green] at (0.3) is [rgba(0, 125, 0, 0.301961) 6px 6px 6px] assert_equals: expected "rgba ( 0 , 128 , 0 , 0.3 ) 6px 6px 6px " but got "rgba ( 0 , 125 , 0 , 0.3 ) 6px 6px 6px "
@@ -36,12 +36,12 @@
 PASS CSS Transitions: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (0.6) is [rgb(0, 77, 0) 10px 10px 10px] 
 PASS CSS Transitions: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (1) is [rgb(0, 128, 0) 10px 10px 10px] 
 PASS CSS Transitions: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (1.5) is [rgb(0, 192, 0) 10px 10px 10px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (-0.3) is [rgb(255, 176, 0) 7px 33px 7px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (0) is [rgb(255, 165, 0) 10px 30px 10px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (0.3) is [rgb(179, 154, 0) 13px 27px 13px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (0.6) is [rgb(102, 143, 0) 16px 24px 16px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (1) is [rgb(0, 128, 0) 20px 20px 20px] 
-PASS CSS Animations: property <text-shadow> from [] to [20px 20px 20px green] at (1.5) is [rgb(0, 110, 0) 25px 15px 25px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (-0.3) is [rgb(255, 176, 0) 7px 33px 7px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0) is [rgb(255, 165, 0) 10px 30px 10px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0.3) is [rgb(179, 154, 0) 13px 27px 13px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0.6) is [rgb(102, 143, 0) 16px 24px 16px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (1) is [rgb(0, 128, 0) 20px 20px 20px] 
+PASS CSS Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (1.5) is [rgb(0, 110, 0) 25px 15px 25px] 
 PASS CSS Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px] 
 PASS CSS Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (0) is [none] 
 PASS CSS Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (0.3) is [rgba(0, 128, 0, 0.301961) 6px 6px 6px] 
@@ -72,6 +72,12 @@
 PASS CSS Animations: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (0.6) is [rgb(0, 77, 0) 10px 10px 10px] 
 PASS CSS Animations: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (1) is [rgb(0, 128, 0) 10px 10px 10px] 
 PASS CSS Animations: property <text-shadow> from [10px 10px 10px black] to [10px 10px 10px currentColor] at (1.5) is [rgb(0, 192, 0) 10px 10px 10px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (-0.3) is [rgb(255, 176, 0) 7px 33px 7px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0) is [rgb(255, 165, 0) 10px 30px 10px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0.3) is [rgb(179, 154, 0) 13px 27px 13px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (0.6) is [rgb(102, 143, 0) 16px 24px 16px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (1) is [rgb(0, 128, 0) 20px 20px 20px] 
+PASS Web Animations: property <text-shadow> from neutral to [20px 20px 20px green] at (1.5) is [rgb(0, 110, 0) 25px 15px 25px] 
 PASS Web Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (-0.3) is [rgba(0, 0, 0, 0) -6px -6px 0px] 
 PASS Web Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (0) is [none] 
 PASS Web Animations: property <text-shadow> from [initial] to [20px 20px 20px green] at (0.3) is [rgba(0, 128, 0, 0.301961) 6px 6px 6px] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation.html
index 5ede603..13fdd3b 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/text-shadow-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: 'text-shadow',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px 20px green',
 }, [
   {at: -0.3, is: 'rgb(255, 176, 0) 7px 33px 7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/top-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/top-interpolation.html
index 80f1e41..96d9b0e4 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/top-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/top-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'top',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation.html
index fa14b356..175bda21 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/transform-interpolation.html
@@ -38,7 +38,7 @@
 <script>
 assertInterpolation({
   property: 'transform',
-  from: '',
+  from: neutralKeyframe,
   to: 'translate(20px)',
 }, [
   {at: -1, is: 'translate(0px)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/transform-origin-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/transform-origin-interpolation.html
index 202f29de..5265ab5 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/transform-origin-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/transform-origin-interpolation.html
@@ -25,7 +25,7 @@
 <script>
 assertInterpolation({
   property: 'transform-origin',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px',
 }, [
   {at: -0.3, is: '7px 33px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/translate-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/translate-interpolation.html
index 456c26991b..9c367c8 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/translate-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/translate-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: 'translate',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -1, is: '0px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/vertical-align-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/vertical-align-interpolation.html
index 6344a41..870248b7 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/vertical-align-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/vertical-align-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: 'vertical-align',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.5, is: '-5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-clip-path-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-clip-path-interpolation.html
index fc44e248..1502bea 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-clip-path-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-clip-path-interpolation.html
@@ -21,7 +21,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-clip-path',
-  from: '',
+  from: neutralKeyframe,
   to: 'inset(20px)',
 }, [
   {at: -0.3, is: 'inset(7px)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-count-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-count-interpolation.html
index dbbbc34..977c0f8 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-count-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-count-interpolation.html
@@ -26,7 +26,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-column-count',
-  from: '',
+  from: neutralKeyframe,
   to: '5',
 }, [
   {at: -0.4, is: '11'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-gap-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-gap-interpolation.html
index f95be916..43c2520f 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-gap-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-gap-interpolation.html
@@ -27,7 +27,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-column-gap',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.3, is: '1px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-color-interpolation.html
index 2c3b8c1d7..195ac25 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-color-interpolation.html
@@ -29,7 +29,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-column-rule-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'lime',
 }, [
   {at: -5, is: 'rgb(255, 255, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-width-interpolation.html
index 86f6ac4..dfddf51c 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-rule-width-interpolation.html
@@ -28,7 +28,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-column-rule-width',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.3, is: '1px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-width-interpolation.html
index bf05326c..ffc213c 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-column-width-interpolation.html
@@ -34,7 +34,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-column-width',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.3, is: '1px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-outset-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-outset-interpolation.html
index 3bd6194..ee89f7e 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-outset-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-outset-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-mask-box-image-outset',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-slice-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-slice-interpolation.html
index f9e4905d..2973101 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-slice-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-slice-interpolation.html
@@ -23,7 +23,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-mask-box-image-slice',
-  from: '',
+  from: neutralKeyframe,
   to: '20%',
 }, [
   {at: -0.3, is: '7%'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation-expected.txt
index 5f0aed4b..4237f70 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
-PASS CSS Transitions: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
+PASS CSS Transitions: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (0) is [url(file:///.../green-100.png)] 
 PASS CSS Transitions: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (0.3) is [url(file:///.../green-100.png)] 
@@ -56,13 +56,13 @@
 FAIL CSS Transitions: property <-webkit-mask-box-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (0.6) is [linear-gradient(45deg, blue, orange)] assert_equals: expected "- webkit - cross - fade ( linear - gradient ( - 45deg , red , yellow ) , linear - gradient ( 45deg , blue , orange ) , 0.6 ) " but got "linear - gradient ( 45deg , blue , orange ) "
 PASS CSS Transitions: property <-webkit-mask-box-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1) is [linear-gradient(45deg, blue, orange)] 
 PASS CSS Transitions: property <-webkit-mask-box-image-source> from [linear-gradient(-45deg, red, yellow)] to [linear-gradient(45deg, blue, orange)] at (1.5) is [linear-gradient(45deg, blue, orange)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
-PASS CSS Animations: property <-webkit-mask-box-image-source> from [] to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (-0.3) is [url(file:///.../stripes-100.png)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0) is [url(file:///.../stripes-100.png)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.3)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.5)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-100.png), url(file:///.../green-100.png), 0.6)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (1) is [url(file:///.../green-100.png)] 
+PASS CSS Animations: property <-webkit-mask-box-image-source> from neutral to [url(../resources/green-100.png)] at (1.5) is [url(file:///.../green-100.png)] 
 PASS CSS Animations: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (-0.3) is [none] 
 PASS CSS Animations: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-mask-box-image-source> from [initial] to [url(../resources/green-100.png)] at (0.3) is [none] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation.html
index 43060a6..3c82c02 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-source-interpolation.html
@@ -40,7 +40,7 @@
 
 // neutral
 assertCrossfadeInterpolation({
-  from: '',
+  from: neutralKeyframe,
   fromComputed: 'url(../resources/stripes-100.png)',
   to: 'url(../resources/green-100.png)',
 });
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-width-interpolation.html
index 2e09f75..f719bc5 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-box-image-width-interpolation.html
@@ -22,7 +22,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-mask-box-image-width',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation-expected.txt
index 4a9015ad..73e762a7 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (-0.3) is [url(file:///.../stripes-20.png)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0) is [url(file:///.../stripes-20.png)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.3)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.5)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.6)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (1) is [url(file:///.../green-20.png)] 
-PASS CSS Transitions: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (1.5) is [url(file:///.../green-20.png)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (-0.3) is [url(file:///.../stripes-20.png)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0) is [url(file:///.../stripes-20.png)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.3)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.5)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.6)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (1) is [url(file:///.../green-20.png)] 
+PASS CSS Transitions: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (1.5) is [url(file:///.../green-20.png)] 
 PASS CSS Transitions: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (-0.3) is [url(file:///.../green-20.png)] 
 PASS CSS Transitions: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (0) is [url(file:///.../green-20.png)] 
 PASS CSS Transitions: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (0.3) is [url(file:///.../green-20.png)] 
@@ -75,13 +75,13 @@
 PASS CSS Transitions: property <-webkit-mask-image> from [url(../resources/blue-20.png), none] to [url(../resources/stripes-20.png), url(../resources/blue-20.png)] at (0.6) is [url(file:///.../stripes-20.png), url(file:///.../blue-20.png)] 
 PASS CSS Transitions: property <-webkit-mask-image> from [url(../resources/blue-20.png), none] to [url(../resources/stripes-20.png), url(../resources/blue-20.png)] at (1) is [url(file:///.../stripes-20.png), url(file:///.../blue-20.png)] 
 PASS CSS Transitions: property <-webkit-mask-image> from [url(../resources/blue-20.png), none] to [url(../resources/stripes-20.png), url(../resources/blue-20.png)] at (1.5) is [url(file:///.../stripes-20.png), url(file:///.../blue-20.png)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (-0.3) is [url(file:///.../stripes-20.png)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0) is [url(file:///.../stripes-20.png)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.3)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.5)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.6)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (1) is [url(file:///.../green-20.png)] 
-PASS CSS Animations: property <-webkit-mask-image> from [] to [url(../resources/green-20.png)] at (1.5) is [url(file:///.../green-20.png)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (-0.3) is [url(file:///.../stripes-20.png)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0) is [url(file:///.../stripes-20.png)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.3) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.3)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.5) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.5)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (0.6) is [-webkit-cross-fade(url(file:///.../stripes-20.png), url(file:///.../green-20.png), 0.6)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (1) is [url(file:///.../green-20.png)] 
+PASS CSS Animations: property <-webkit-mask-image> from neutral to [url(../resources/green-20.png)] at (1.5) is [url(file:///.../green-20.png)] 
 PASS CSS Animations: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (-0.3) is [none] 
 PASS CSS Animations: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (0) is [none] 
 PASS CSS Animations: property <-webkit-mask-image> from [initial] to [url(../resources/green-20.png)] at (0.3) is [none] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation.html
index e9d5cef6..d5c7191 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-image-interpolation.html
@@ -38,7 +38,7 @@
 
 // neutral
 assertCrossfadeInterpolation({
-  from: '',
+  from: neutralKeyframe,
   fromComputed: 'url(../resources/stripes-20.png)',
   to: 'url(../resources/green-20.png)',
 });
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-position-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-position-interpolation.html
index 389392a..206c53d 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-position-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-position-interpolation.html
@@ -30,7 +30,7 @@
 // neutral
 assertInterpolation({
   property: '-webkit-mask-position',
-  from: '',
+  from: neutralKeyframe,
   to: '20px 20px',
 }, [
   {at: -0.25, is: '7.5px 32.5px, 7.5px 32.5px, 7.5px 32.5px, 7.5px 32.5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-size-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-size-interpolation.html
index 1894880..839a909 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-size-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-mask-size-interpolation.html
@@ -28,7 +28,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-mask-size',
-  from: '',
+  from: neutralKeyframe,
   to: '200px 250px',
 }, [
   {at: -0.25, is: '75px 62.5px, 75px 62.5px, 75px 62.5px, 75px 62.5px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-text-stroke-color-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-text-stroke-color-interpolation.html
index 3026428..94e02eb 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/webkit-text-stroke-color-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/webkit-text-stroke-color-interpolation.html
@@ -20,7 +20,7 @@
 <script>
 assertInterpolation({
   property: '-webkit-text-stroke-color',
-  from: '',
+  from: neutralKeyframe,
   to: 'green',
 }, [
   {at: -0.3, is: 'rgb(255, 176, 0)'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/widows-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/widows-interpolation.html
index ccf78cbb..29a2d9e 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/widows-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/widows-interpolation.html
@@ -12,7 +12,7 @@
 <script>
 assertInterpolation({
   property: 'widows',
-  from: '',
+  from: neutralKeyframe,
   to: '20',
 }, [
   {at: -3, is: '1'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/width-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/width-interpolation.html
index 294b43b..dccb204 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/width-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/width-interpolation.html
@@ -24,7 +24,7 @@
 <script>
 assertInterpolation({
   property: 'width',
-  from: '',
+  from: neutralKeyframe,
   to: '40px',
 }, [
   {at: -0.3, is: '1px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/word-spacing-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/word-spacing-interpolation.html
index cc09897..d04d3b3 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/word-spacing-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/word-spacing-interpolation.html
@@ -18,7 +18,7 @@
 <script>
 assertInterpolation({
   property: 'word-spacing',
-  from: '',
+  from: neutralKeyframe,
   to: '20px',
 }, [
   {at: -0.3, is: '7px'},
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation-expected.txt b/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation-expected.txt
index be3c4d7..99b59bb2 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation-expected.txt
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation-expected.txt
@@ -1,11 +1,11 @@
 This is a testharness.js-based test.
 PASS This test uses interpolation-test.js. 
-PASS CSS Transitions: property <z-index> from [] to [5] at (-0.3) is [-4] 
-PASS CSS Transitions: property <z-index> from [] to [5] at (0) is [-2] 
-PASS CSS Transitions: property <z-index> from [] to [5] at (0.3) is [0] 
-PASS CSS Transitions: property <z-index> from [] to [5] at (0.6) is [2] 
-PASS CSS Transitions: property <z-index> from [] to [5] at (1) is [5] 
-PASS CSS Transitions: property <z-index> from [] to [5] at (1.5) is [9] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (-0.3) is [-4] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (0) is [-2] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (0.3) is [0] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (0.6) is [2] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (1) is [5] 
+PASS CSS Transitions: property <z-index> from neutral to [5] at (1.5) is [9] 
 PASS CSS Transitions: property <z-index> from [initial] to [5] at (-0.3) is [5] 
 PASS CSS Transitions: property <z-index> from [initial] to [5] at (0) is [5] 
 PASS CSS Transitions: property <z-index> from [initial] to [5] at (0.3) is [5] 
@@ -52,12 +52,12 @@
 PASS CSS Transitions: property <z-index> from [auto] to [10] at (0.6) is [10] 
 PASS CSS Transitions: property <z-index> from [auto] to [10] at (1) is [10] 
 PASS CSS Transitions: property <z-index> from [auto] to [10] at (1.5) is [10] 
-PASS CSS Animations: property <z-index> from [] to [5] at (-0.3) is [-4] 
-PASS CSS Animations: property <z-index> from [] to [5] at (0) is [-2] 
-PASS CSS Animations: property <z-index> from [] to [5] at (0.3) is [0] 
-PASS CSS Animations: property <z-index> from [] to [5] at (0.6) is [2] 
-PASS CSS Animations: property <z-index> from [] to [5] at (1) is [5] 
-PASS CSS Animations: property <z-index> from [] to [5] at (1.5) is [9] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (-0.3) is [-4] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (0) is [-2] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (0.3) is [0] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (0.6) is [2] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (1) is [5] 
+PASS CSS Animations: property <z-index> from neutral to [5] at (1.5) is [9] 
 PASS CSS Animations: property <z-index> from [initial] to [5] at (-0.3) is [auto] 
 PASS CSS Animations: property <z-index> from [initial] to [5] at (0) is [auto] 
 PASS CSS Animations: property <z-index> from [initial] to [5] at (0.3) is [auto] 
@@ -104,6 +104,12 @@
 PASS CSS Animations: property <z-index> from [auto] to [10] at (0.6) is [10] 
 PASS CSS Animations: property <z-index> from [auto] to [10] at (1) is [10] 
 PASS CSS Animations: property <z-index> from [auto] to [10] at (1.5) is [10] 
+PASS Web Animations: property <z-index> from neutral to [5] at (-0.3) is [-4] 
+PASS Web Animations: property <z-index> from neutral to [5] at (0) is [-2] 
+PASS Web Animations: property <z-index> from neutral to [5] at (0.3) is [0] 
+PASS Web Animations: property <z-index> from neutral to [5] at (0.6) is [2] 
+PASS Web Animations: property <z-index> from neutral to [5] at (1) is [5] 
+PASS Web Animations: property <z-index> from neutral to [5] at (1.5) is [9] 
 PASS Web Animations: property <z-index> from [initial] to [5] at (-0.3) is [auto] 
 PASS Web Animations: property <z-index> from [initial] to [5] at (0) is [auto] 
 PASS Web Animations: property <z-index> from [initial] to [5] at (0.3) is [auto] 
diff --git a/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation.html b/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation.html
index bc87d85..155f316 100644
--- a/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation.html
+++ b/third_party/WebKit/LayoutTests/animations/interpolation/z-index-interpolation.html
@@ -45,7 +45,7 @@
 
 assertInterpolation({
   property: 'z-index',
-  from: '',
+  from: neutralKeyframe,
   to: '5',
 }, [
   {at: -0.3, is: '-4'},
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/backdrop-filter-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/backdrop-filter-responsive.html
new file mode 100644
index 0000000..96f6bb0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/responsive/backdrop-filter-responsive.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<script src="resources/responsive-test.js"></script>
+<script>
+assertCSSResponsive({
+  property: 'backdrop-filter',
+  from: neutralKeyframe,
+  to: 'blur(10px)',
+  configurations: [{
+    state: {underlying: 'blur(50px)'},
+    expect: [
+      {at: 0.25, is: 'blur(40px)'},
+      {at: 0.75, is: 'blur(20px)'},
+    ],
+  }, {
+    state: {underlying: 'opacity(50%)'},
+    expect: [
+      {at: 0.25, is: 'opacity(0.5)'},
+      {at: 0.75, is: 'blur(10px)'},
+    ],
+  }],
+});
+
+assertCSSResponsive({
+  property: 'backdrop-filter',
+  from: 'inherit',
+  to: 'blur(10px)',
+  configurations: [{
+    state: {inherited: 'blur(50px)'},
+    expect: [
+      {at: 0.25, is: 'blur(40px)'},
+      {at: 0.75, is: 'blur(20px)'},
+    ],
+  }, {
+    state: {inherited: 'opacity(50%)'},
+    expect: [
+      {at: 0.25, is: 'opacity(0.5)'},
+      {at: 0.75, is: 'blur(10px)'},
+    ],
+  }],
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html
index 094a1f3..bda45539 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/color-responsive.html
@@ -39,7 +39,7 @@
   }],
 });
 
-assertResponsive({
+assertCSSResponsive({
   property: 'color',
   from: 'green',
   to: 'currentcolor',
diff --git a/third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html b/third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html
index 7ada8b4..2d18846 100644
--- a/third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html
+++ b/third_party/WebKit/LayoutTests/animations/responsive/stroke-dasharray-responsive.html
@@ -3,7 +3,7 @@
 <script>
 assertCSSResponsive({
   property: 'stroke-dasharray',
-  from: '',
+  from: neutralKeyframe,
   to: '80px',
   configurations: [{
     state: {underlying: '20px, 40px'},
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-mode-composition.html b/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-mode-composition.html
index b3eb412..f4245407 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-mode-composition.html
+++ b/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-mode-composition.html
@@ -11,7 +11,7 @@
 'use strict';
 assertAttributeInterpolation({
   property: 'mode',
-  underlying: 'multiply'
+  underlying: 'multiply',
   from: 'screen',
   fromComposite: 'add',
   to: 'lighten',
@@ -27,7 +27,7 @@
 
 assertAttributeInterpolation({
   property: 'mode',
-  underlying: 'multiply'
+  underlying: 'multiply',
   from: neutralKeyframe,
   to: 'lighten',
   toComposite: 'replace',
diff --git a/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html b/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html
index 91ab8cde..6a2b013c 100644
--- a/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html
+++ b/third_party/WebKit/LayoutTests/animations/svg-attribute-composition/svg-targetX-targetY-composition.html
@@ -14,7 +14,7 @@
   underlying: '128',
   from: '-32',
   fromComposite: 'add',
-  to: '1029'
+  to: '1029',
   toComposite: 'add',
 }, [
   {at: -0.4, is: -328},
@@ -30,7 +30,7 @@
   underlying: '-37',
   from: '18',
   fromComposite: 'replace',
-  to: '1'
+  to: '1',
   toComposite: 'add',
 }, [
   {at: -0.4, is: 40},
@@ -44,7 +44,8 @@
 assertAttributeInterpolation({
   property: 'targetX',
   underlying: '2',
-  to: '-99'
+  from: neutralKeyframe,
+  to: '-99',
   toComposite: 'replace',
 }, [
   {at: -0.4, is: 42},
@@ -61,7 +62,7 @@
   underlying: '128',
   from: '-32',
   fromComposite: 'add',
-  to: '1029'
+  to: '1029',
   toComposite: 'add',
 }, [
   {at: -0.4, is: -328},
@@ -77,7 +78,7 @@
   underlying: '-37',
   from: '18',
   fromComposite: 'replace',
-  to: '1'
+  to: '1',
   toComposite: 'add',
 }, [
   {at: -0.4, is: 40},
@@ -91,7 +92,8 @@
 assertAttributeInterpolation({
   property: 'targetY',
   underlying: '2',
-  to: '-99'
+  from: neutralKeyframe,
+  to: '-99',
   toComposite: 'replace',
 }, [
   {at: -0.4, is: 42},
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment-rtl.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment-rtl.html
new file mode 100644
index 0000000..e8a1285f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment-rtl.html
@@ -0,0 +1,399 @@
+<!DOCTYPE html>
+<html>
+<link href="resources/grid.css" rel="stylesheet">
+<link href="resources/grid-alignment.css" rel="stylesheet">
+<style>
+
+.grid {
+    grid-template-columns: 100px 50px;
+    grid-template-rows: 70px 30px;
+    width: 400px;
+    height: 200px;
+    margin: 5px;
+    /* Ensures that the grid container is the containing block of the absolutely positioned grid children. */
+    position: relative;
+}
+
+.grid > div {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background-color: lime;
+}
+
+.offsets {
+    left: 0;
+    top: 0;
+}
+
+</style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/check-layout-th.js"></script>
+<body onload="checkLayout('.grid')">
+<div id="log"></div>
+
+<p>This test checks the behavior of the positioned items in a grid using content alignment in RTL.</p>
+
+<div class="grid directionRTL contentStart">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="175" data-offset-y="50" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="175" data-offset-y="50" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="50" data-offset-y="100" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="50" data-offset-y="100" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="238" data-offset-y="25" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="238" data-offset-y="25" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="217" data-offset-y="33" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="217" data-offset-y="33" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="250" data-offset-y="70" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="250" data-offset-y="70" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="125" data-offset-y="120" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="125" data-offset-y="120" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="63" data-offset-y="145" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="63" data-offset-y="145" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="83" data-offset-y="137" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="83" data-offset-y="137" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="175" data-offset-y="0" data-expected-width="225" data-expected-height="120">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="175" data-offset-y="0" data-expected-width="225" data-expected-height="120">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="50" data-offset-y="0" data-expected-width="350" data-expected-height="170">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="50" data-offset-y="0" data-expected-width="350" data-expected-height="170">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="300" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="238" data-offset-y="0" data-expected-width="162" data-expected-height="95">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="238" data-offset-y="0" data-expected-width="162" data-expected-height="95">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="217" data-offset-y="0" data-expected-width="183" data-expected-height="103">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="217" data-offset-y="0" data-expected-width="183" data-expected-height="103">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="70" data-expected-width="300" data-expected-height="130">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="70" data-expected-width="300" data-expected-height="130">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="120" data-expected-width="175" data-expected-height="80">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="120" data-expected-width="175" data-expected-height="80">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="145" data-expected-width="113" data-expected-height="55">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="145" data-expected-width="113" data-expected-height="55">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="137" data-expected-width="133" data-expected-height="63">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="0" data-offset-y="137" data-expected-width="133" data-expected-height="63">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentStart">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentCenter">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentEnd">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceBetween">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceAround">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid directionRTL contentSpaceEvenly">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment.html b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment.html
new file mode 100644
index 0000000..cf98349
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css-grid-layout/grid-positioned-items-content-alignment.html
@@ -0,0 +1,399 @@
+<!DOCTYPE html>
+<html>
+<link href="resources/grid.css" rel="stylesheet">
+<link href="resources/grid-alignment.css" rel="stylesheet">
+<style>
+
+.grid {
+    grid-template-columns: 100px 50px;
+    grid-template-rows: 70px 30px;
+    width: 400px;
+    height: 200px;
+    margin: 5px;
+    /* Ensures that the grid container is the containing block of the absolutely positioned grid children. */
+    position: relative;
+}
+
+.grid > div {
+    position: absolute;
+    width: 100%;
+    height: 100%;
+    background-color: lime;
+}
+
+.offsets {
+    left: 0;
+    top: 0;
+}
+
+</style>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="../../resources/check-layout-th.js"></script>
+<body onload="checkLayout('.grid')">
+<div id="log"></div>
+
+<p>This test checks the behavior of the positioned items in a grid using content alignment.</p>
+
+<div class="grid contentStart">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="125" data-offset-y="50" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="125" data-offset-y="50" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="250" data-offset-y="100" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="250" data-offset-y="100" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="63" data-offset-y="25" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="63" data-offset-y="25" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="83" data-offset-y="33" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 1 / 2; grid-row: 1 / 2;"
+        data-offset-x="83" data-offset-y="33" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="100" data-offset-y="70" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="100" data-offset-y="70" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="225" data-offset-y="120" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="225" data-offset-y="120" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="288" data-offset-y="145" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="288" data-offset-y="145" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="267" data-offset-y="137" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 2 / 3; grid-row: 2 / 3;"
+        data-offset-x="267" data-offset-y="137" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="225" data-expected-height="120">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="225" data-expected-height="120">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="350" data-expected-height="170">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="350" data-expected-height="170">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="100" data-expected-height="70">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="163" data-expected-height="95">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="163" data-expected-height="95">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="183" data-expected-height="103">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div class="offsets" style="grid-column: auto / 2; grid-row: auto / 2;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="183" data-expected-height="103">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="100" data-offset-y="70" data-expected-width="300" data-expected-height="130">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="100" data-offset-y="70" data-expected-width="300" data-expected-height="130">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="225" data-offset-y="120" data-expected-width="175" data-expected-height="80">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="225" data-offset-y="120" data-expected-width="175" data-expected-height="80">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="350" data-offset-y="170" data-expected-width="50" data-expected-height="30">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="288" data-offset-y="145" data-expected-width="112" data-expected-height="55">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="288" data-offset-y="145" data-expected-width="112" data-expected-height="55">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="267" data-offset-y="137" data-expected-width="133" data-expected-height="63">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div class="offsets" style="grid-column: 2 / auto; grid-row: 2 / auto;"
+        data-offset-x="267" data-offset-y="137" data-expected-width="133" data-expected-height="63">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentStart">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentCenter">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentEnd">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceBetween">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceAround">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+<div class="grid contentSpaceEvenly">
+    <div class="offsets" style="grid-column: auto / auto; grid-row: auto / auto;"
+        data-offset-x="0" data-offset-y="0" data-expected-width="400" data-expected-height="200">
+    </div>
+</div>
+
+</body>
+</html>
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
new file mode 100644
index 0000000..7afc875
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/README.md
@@ -0,0 +1,4 @@
+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
new file mode 100644
index 0000000..d5b5f82c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate-expected.txt
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 0000000..afc9221
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animatable/animate.html
@@ -0,0 +1,143 @@
+<!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
new file mode 100644
index 0000000..3d369b24
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration-expected.txt
@@ -0,0 +1,35 @@
+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
new file mode 100644
index 0000000..662ff40
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/duration.html
@@ -0,0 +1,149 @@
+<!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
new file mode 100644
index 0000000..c41bd697
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/endDelay.html
@@ -0,0 +1,98 @@
+<!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
new file mode 100644
index 0000000..c6b3964
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations-expected.txt
@@ -0,0 +1,7 @@
+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
new file mode 100644
index 0000000..fb47ae8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getAnimations.html
@@ -0,0 +1,78 @@
+<!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
new file mode 100644
index 0000000..58d9dff6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle-expected.txt
@@ -0,0 +1,8 @@
+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
new file mode 100644
index 0000000..278392c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/getComputedStyle.html
@@ -0,0 +1,107 @@
+<!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
new file mode 100644
index 0000000..bf47a38dc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart-expected.txt
@@ -0,0 +1,8 @@
+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
new file mode 100644
index 0000000..21e73e1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-effect-timing/iterationStart.html
@@ -0,0 +1,72 @@
+<!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
new file mode 100644
index 0000000..80d9de7b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after-expected.txt
@@ -0,0 +1,19 @@
+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
new file mode 100644
index 0000000..3db07eee
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-after.html
@@ -0,0 +1,419 @@
+<!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
new file mode 100644
index 0000000..f2e2ebf4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before-expected.txt
@@ -0,0 +1,19 @@
+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
new file mode 100644
index 0000000..22caa02
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-before.html
@@ -0,0 +1,418 @@
+<!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
new file mode 100644
index 0000000..9625203
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling-expected.txt
@@ -0,0 +1,25 @@
+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
new file mode 100644
index 0000000..8a6b4a8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-next-sibling.html
@@ -0,0 +1,503 @@
+<!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
new file mode 100644
index 0000000..0602142
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent-expected.txt
@@ -0,0 +1,6 @@
+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
new file mode 100644
index 0000000..1c4ac6f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-parent.html
@@ -0,0 +1,53 @@
+<!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
new file mode 100644
index 0000000..3a790fa
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling-expected.txt
@@ -0,0 +1,25 @@
+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
new file mode 100644
index 0000000..16f1936
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-previous-sibling.html
@@ -0,0 +1,511 @@
+<!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
new file mode 100644
index 0000000..46be5d3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove-expected.txt
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..97f657e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-remove.html
@@ -0,0 +1,239 @@
+<!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
new file mode 100644
index 0000000..9379969
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace-expected.txt
@@ -0,0 +1,20 @@
+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
new file mode 100644
index 0000000..f4cebc4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/animation-node-replace.html
@@ -0,0 +1,444 @@
+<!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
new file mode 100644
index 0000000..d99a105
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-node/idlharness.html
@@ -0,0 +1,54 @@
+<!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
new file mode 100644
index 0000000..3f57329d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/document-timeline.html
@@ -0,0 +1,89 @@
+<!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
new file mode 100644
index 0000000..977c872
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness-expected.txt
@@ -0,0 +1,18 @@
+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
new file mode 100644
index 0000000..7ca3530
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation-timeline/idlharness.html
@@ -0,0 +1,29 @@
+<!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
new file mode 100644
index 0000000..2ea07710
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/animation/constructor.html
@@ -0,0 +1,59 @@
+<!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
new file mode 100644
index 0000000..ebc9f02
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor-expected.txt
@@ -0,0 +1,109 @@
+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
new file mode 100644
index 0000000..142ec337
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/constructor.html
@@ -0,0 +1,601 @@
+<!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
new file mode 100644
index 0000000..2f6daba
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing-expected.txt
@@ -0,0 +1,24 @@
+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
new file mode 100644
index 0000000..9e518efb
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/effect-easing.html
@@ -0,0 +1,438 @@
+<!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
new file mode 100644
index 0000000..e951bfd1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-currentIteration.html
@@ -0,0 +1,445 @@
+<!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
new file mode 100644
index 0000000..4324d72
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-expected.txt
@@ -0,0 +1,44 @@
+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
new file mode 100644
index 0000000..4cecc1d
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming-progress.html
@@ -0,0 +1,445 @@
+<!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
new file mode 100644
index 0000000..5f4c602
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/getComputedTiming.html
@@ -0,0 +1,227 @@
+<!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
new file mode 100644
index 0000000..52d4f89
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling-expected.txt
@@ -0,0 +1,5 @@
+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
new file mode 100644
index 0000000..613933c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/keyframe-effect/keyframe-handling.html
@@ -0,0 +1,75 @@
+<!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
new file mode 100644
index 0000000..e7179cc1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/imported/web-platform-tests/web-animations/testcommon.js
@@ -0,0 +1,166 @@
+/*
+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/inspector-protocol/console/exception-from-worker-contains-stack-expected.txt b/third_party/WebKit/LayoutTests/inspector-protocol/console/exception-from-worker-contains-stack-expected.txt
new file mode 100644
index 0000000..44e1f4f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/exception-from-worker-contains-stack-expected.txt
@@ -0,0 +1,6 @@
+CONSOLE ERROR: line 3: Uncaught Error
+Tests that console message from worker contains stack trace.
+Worker created
+Worker created
+Message with stack trace received.
+
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/exception-from-worker-contains-stack.html b/third_party/WebKit/LayoutTests/inspector-protocol/console/exception-from-worker-contains-stack.html
new file mode 100644
index 0000000..88a3050
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/exception-from-worker-contains-stack.html
@@ -0,0 +1,78 @@
+<html>
+<head>
+<script type="text/javascript" src="../../http/tests/inspector-protocol/inspector-protocol-test.js"></script>
+<script>
+
+var worker1;
+var worker2;
+
+function startWorkers()
+{
+    worker1 = new Worker("resources/worker-with-throw.js");
+    worker1.onerror = function(e) {
+        e.preventDefault();
+        worker1.terminate();
+    }
+    worker2 = new Worker("resources/worker-with-throw.js");
+}
+
+function test()
+{
+    InspectorTest.sendCommandOrDie("Console.enable", {});
+    InspectorTest.sendCommandOrDie("Worker.enable", {}, didEnableWorkerDebugging);
+
+    function didEnableWorkerDebugging(event)
+    {
+        InspectorTest.sendCommandOrDie("Runtime.evaluate", { expression: "startWorkers()" });
+    }
+
+    var workerRequestId = 1;
+    function sendCommandToWorker(method, params, workerId)
+    {
+        InspectorTest.sendCommand("Worker.sendMessageToWorker",
+            {
+                "workerId": workerId,
+                "message": JSON.stringify({ "method": method,
+                                            "params": params,
+                                            "id": workerRequestId++ })
+            });
+    }
+
+    var waitForWorkers = 2;
+    InspectorTest.eventHandler["Worker.workerCreated"] = function(messageObject)
+    {
+        var workerId = messageObject["params"]["workerId"];
+        InspectorTest.log("Worker created");
+        sendCommandToWorker("Console.enable", {}, workerId);
+        if (!--waitForWorkers)
+            InspectorTest.sendCommandOrDie("Runtime.evaluate", { expression: "worker1.postMessage(239);worker2.postMessage(42);" });
+    }
+
+    var workerTerminated = false;
+    var messageReceived = false;
+    InspectorTest.eventHandler["Worker.dispatchMessageFromWorker"] = function(messageObject)
+    {
+        var message = JSON.parse(messageObject["params"]["message"]);
+        if (message["method"] === "Console.messageAdded") {
+            var callFrames = message.params.message.stack.callFrames;
+            if (callFrames.length < 2 || callFrames[1].functionName !== "boo1")
+                return;
+            InspectorTest.log(message.params.message.stack.callFrames.length > 0 ? "Message with stack trace received." : "[FAIL] Message contains empty stack trace");
+            messageReceived = true;
+            if (messageReceived && workerTerminated)
+                InspectorTest.completeTest();
+        }
+    }
+
+    InspectorTest.eventHandler["Worker.workerTerminated"] = function(messageObject)
+    {
+        InspectorTest.eventHandler["Worker.workerTerminated"] = undefined;
+        workerTerminated = true;
+        if (messageReceived && workerTerminated)
+            InspectorTest.completeTest();
+    }
+}
+</script>
+</head>
+<body onload="runTest()">Tests that console message from worker contains stack trace.</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/inspector-protocol/console/resources/worker-with-throw.js b/third_party/WebKit/LayoutTests/inspector-protocol/console/resources/worker-with-throw.js
new file mode 100644
index 0000000..d0c8d2c
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/inspector-protocol/console/resources/worker-with-throw.js
@@ -0,0 +1,21 @@
+function foo()
+{
+    throw new Error();
+}
+
+function boo1()
+{
+    foo();
+}
+
+function boo2()
+{
+    foo();
+}
+
+onmessage = function(event) {
+    if (event.data === 42)
+        boo1();
+    else
+        boo2();
+};
diff --git a/third_party/WebKit/LayoutTests/inspector/console/resources/worker-with-throw.js b/third_party/WebKit/LayoutTests/inspector/console/resources/worker-with-throw.js
deleted file mode 100644
index 5d8503d..0000000
--- a/third_party/WebKit/LayoutTests/inspector/console/resources/worker-with-throw.js
+++ /dev/null
@@ -1,12 +0,0 @@
-function foo()
-{
-    throw new Error();
-}
-function boo()
-{
-    foo();
-}
-
-onmessage = function(event) {
-    boo();
-};
\ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack-expected.txt b/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack-expected.txt
deleted file mode 100644
index aec305f..0000000
--- a/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-CONSOLE ERROR: line 3: Uncaught Error
-CONSOLE MESSAGE: line 18: Uncaught Error
-Tests exception message from worker contains stack trace.
-
-worker-with-throw.js:3 Uncaught Errorfoo @ worker-with-throw.js:3boo @ worker-with-throw.js:7onmessage @ worker-with-throw.js:11
-worker-exception-message-contains-stack.html:18 Uncaught Error
-
diff --git a/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack.html b/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack.html
deleted file mode 100644
index 7f4b878f..0000000
--- a/third_party/WebKit/LayoutTests/inspector/console/worker-exception-message-contains-stack.html
+++ /dev/null
@@ -1,65 +0,0 @@
-<html>
-<head>
-<script src="../../http/tests/inspector/inspector-test.js"></script>
-<script src="../../http/tests/inspector/console-test.js"></script>
-<script>
-var worker1;
-var worker2;
-
-function startWorker1()
-{
-    worker1 = new Worker("resources/worker-with-throw.js");
-}
-
-function startWorker2()
-{
-    worker2 = new Worker("resources/worker-with-throw.js");
-    worker2.onerror = function(e) {
-        console.log(e.message);
-        e.preventDefault();
-    }
-}
-
-function postMessageToWorker(worker)
-{
-    worker.postMessage("ping");
-}
-
-function test()
-{
-    startWorkerAndPostMessage(step2, "worker1", "startWorker1");
-
-    function step2()
-    {
-        InspectorTest.waitUntilMessageReceived(step3);
-        startWorkerAndPostMessage(undefined, "worker2", "startWorker2");
-    }
-
-    function step3()
-    {
-        InspectorTest.expandConsoleMessages(step4);
-    }
-
-    function step4()
-    {
-        InspectorTest.dumpConsoleMessages();
-        InspectorTest.completeTest();
-    }
-
-    function contextCreated(next, workerName)
-    {
-        InspectorTest.evaluateInPage("postMessageToWorker(" + workerName + ")", next);
-    }
-
-    function startWorkerAndPostMessage(next, workerName, workerStartFunction)
-    {
-        InspectorTest.addSniffer(WebInspector.RuntimeModel.prototype, "_executionContextCreated", contextCreated.bind(this, next, workerName));
-        InspectorTest.evaluateInPage(workerStartFunction + "()");
-    }
-};
-</script>
-</head>
-<body onload="runTest()">
-<p>Tests exception message from worker contains stack trace.</p>
-</body>
-</html>
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/slot-assigned-slot.html b/third_party/WebKit/LayoutTests/shadow-dom/slot-assigned-slot.html
new file mode 100644
index 0000000..66971e8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/shadow-dom/slot-assigned-slot.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<script src='../resources/testharness.js'></script>
+<script src='../resources/testharnessreport.js'></script>
+<script src='../fast/dom/shadow/resources/shadow-dom.js'></script>
+<script src='resources/shadow-dom.js'></script>
+<div id="log"></div>
+<p>
+  document tree: [i0 -> [x-foo]]<br>
+  x-foo's shadow tree: [j1 -> [s1] -> [s2] -> j2 ->[x-bar]]<br>
+  x-bar's shadow tree: [k1 -> [s3]]<br>
+  slot #s1: [i1 -> i2]<br>
+  slot #s2: [i3]<br>
+  slot #s3: [[s4]]<br>
+  slot #s4: [i4 -> i5]<br><br>
+  <b>v1 ideal nav forward:  [i0 -> j1 -> i1 -> i2 -> i3 -> j2 -> x-bar -> k1 -> i4 -> i5]</b><br>
+</p>
+
+<input id="i0" tabindex=0 value="i0">
+<div id="x-foo">
+  <input id="i2" slot="s1" tabindex=2 value="i2">
+  <input id="i1" slot="s1" tabindex=1 value="i1">
+  <input id="i3" slot="s2" tabindex=3 value="i3">
+  <input id="i4" slot="s4" tabindex=4 value="i4">
+  <input id="i5" slot="s4" tabindex=5 value="i5">
+  <template data-mode="open">
+    <div id="x-bar" tabindex=5>
+      <slot id="s4" name="s4" slot="s3"></slot>
+      <template data-mode="open">
+        <slot id="s3" name="s3" tabindex=2></slot>
+        <input id="k1" tabindex=1 value="k1">
+      </template>
+    </div>
+    <input id="j1" tabindex=1 value="j1">
+    <slot id="s2" name="s2" tabindex=3></slot>
+    <slot id="s1" name="s1" tabindex=2></slot>
+    <input id="j2" tabindex=4 value="j2">
+  </template>
+</div>
+
+<script>
+
+test(function() {
+  var xfoo = document.getElementById('x-foo');
+  convertTemplatesToShadowRootsWithin(xfoo);
+
+  var elements = [
+    'i0',
+    'x-foo/j1',
+    'i1',
+    'i2',
+    'i3',
+    'x-foo/j2',
+    'x-foo/x-bar',
+    'x-foo/x-bar/k1',
+    'i4',
+    'i5'
+  ];
+
+  for (var i = 0; i + 1 < elements.length; ++i)
+      assert_true(shouldNavigateFocus(elements[i], elements[i + 1], 'forward'), elements[i] + ' to ' + elements[i + 1]);
+  elements.reverse();
+  for (var i = 0; i + 1 < elements.length; ++i)
+      assert_true(shouldNavigateFocus(elements[i], elements[i + 1], 'backward'), elements[i] + ' to ' + elements[i + 1]);
+}, 'Focus should cover assigned elements of an assigned slot, as well as elements that are directly assigned to a slot.');
+
+</script>
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
index 4307080..810e3fa 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8GCController.cpp
@@ -52,8 +52,8 @@
 #include "platform/TraceEvent.h"
 #include "public/platform/BlameContext.h"
 #include "public/platform/Platform.h"
-#include "wtf/Partitions.h"
 #include "wtf/Vector.h"
+#include "wtf/allocator/Partitions.h"
 #include <algorithm>
 
 namespace blink {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8IdleTaskRunner.h b/third_party/WebKit/Source/bindings/core/v8/V8IdleTaskRunner.h
index 7bc17a5..d4718d4 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8IdleTaskRunner.h
+++ b/third_party/WebKit/Source/bindings/core/v8/V8IdleTaskRunner.h
@@ -32,6 +32,7 @@
 #include "public/platform/Platform.h"
 #include "public/platform/WebScheduler.h"
 #include "public/platform/WebThread.h"
+#include "public/platform/WebTraceLocation.h"
 #include "wtf/OwnPtr.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
index 6535932f..2aae5b22 100644
--- a/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
+++ b/third_party/WebKit/Source/bindings/core/v8/V8Initializer.cpp
@@ -132,6 +132,17 @@
     return emptyString();
 }
 
+static ErrorEvent* createErrorEventFromMesssage(ScriptState* scriptState, v8::Local<v8::Message> message, String resourceName)
+{
+    String errorMessage = toCoreStringWithNullCheck(message->Get());
+    int lineNumber = 0;
+    int columnNumber = 0;
+    if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber)
+        && v8Call(message->GetStartColumn(scriptState->context()), columnNumber))
+        ++columnNumber;
+    return ErrorEvent::create(errorMessage, resourceName, lineNumber, columnNumber, &scriptState->world());
+}
+
 static void messageHandlerInMainThread(v8::Local<v8::Message> message, v8::Local<v8::Value> data)
 {
     ASSERT(isMainThread());
@@ -144,7 +155,7 @@
 
     int scriptId = 0;
     RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scriptId);
-    String resourceName = extractResourceName(message, enteredWindow->document());
+
     AccessControlStatus accessControlStatus = NotSharableCrossOrigin;
     if (message->IsOpaque())
         accessControlStatus = OpaqueResource;
@@ -152,13 +163,9 @@
         accessControlStatus = SharableCrossOrigin;
 
     ScriptState* scriptState = ScriptState::current(isolate);
-    String errorMessage = toCoreStringWithNullCheck(message->Get());
-    int lineNumber = 0;
-    int columnNumber = 0;
-    if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber)
-        && v8Call(message->GetStartColumn(scriptState->context()), columnNumber))
-        ++columnNumber;
-    ErrorEvent* event = ErrorEvent::create(errorMessage, resourceName, lineNumber, columnNumber, &scriptState->world());
+
+    String resourceName = extractResourceName(message, enteredWindow->document());
+    ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, resourceName);
 
     String messageForConsole = extractMessageForConsole(isolate, data);
     if (!messageForConsole.isEmpty())
@@ -421,17 +428,12 @@
     ScriptState* scriptState = ScriptState::current(isolate);
     // During the frame teardown, there may not be a valid context.
     if (ExecutionContext* context = scriptState->getExecutionContext()) {
-        String errorMessage = toCoreStringWithNullCheck(message->Get());
-        TOSTRING_VOID(V8StringResource<>, sourceURL, message->GetScriptOrigin().ResourceName());
+        TOSTRING_VOID(V8StringResource<>, resourceName, message->GetScriptOrigin().ResourceName());
+        ErrorEvent* event = createErrorEventFromMesssage(scriptState, message, resourceName);
+
         int scriptId = 0;
         RefPtr<ScriptCallStack> callStack = extractCallStack(isolate, message, &scriptId);
 
-        int lineNumber = 0;
-        int columnNumber = 0;
-        if (v8Call(message->GetLineNumber(scriptState->context()), lineNumber)
-            && v8Call(message->GetStartColumn(scriptState->context()), columnNumber))
-            ++columnNumber;
-        ErrorEvent* event = ErrorEvent::create(errorMessage, sourceURL, lineNumber, columnNumber, &DOMWrapperWorld::current(isolate));
         AccessControlStatus corsStatus = message->IsSharedCrossOrigin() ? SharableCrossOrigin : NotSharableCrossOrigin;
 
         // If execution termination has been triggered as part of constructing
diff --git a/third_party/WebKit/Source/core/CoreInitializer.cpp b/third_party/WebKit/Source/core/CoreInitializer.cpp
index c55127a8..009f4dd7 100644
--- a/third_party/WebKit/Source/core/CoreInitializer.cpp
+++ b/third_party/WebKit/Source/core/CoreInitializer.cpp
@@ -59,7 +59,7 @@
 #include "platform/weborigin/KURL.h"
 #include "platform/weborigin/SchemeRegistry.h"
 #include "platform/weborigin/SecurityPolicy.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.cpp b/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.cpp
new file mode 100644
index 0000000..00cebb04
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.cpp
@@ -0,0 +1,217 @@
+// 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/animation/CSSFilterListInterpolationType.h"
+
+#include "core/animation/FilterInterpolationFunctions.h"
+#include "core/animation/FilterListPropertyFunctions.h"
+#include "core/animation/ListInterpolationFunctions.h"
+#include "core/css/CSSValueList.h"
+#include "core/css/resolver/StyleResolverState.h"
+
+namespace blink {
+
+namespace {
+
+class UnderlyingFilterListChecker : public InterpolationType::ConversionChecker {
+public:
+    static PassOwnPtr<UnderlyingFilterListChecker> create(PassRefPtr<NonInterpolableList> nonInterpolableList)
+    {
+        return adoptPtr(new UnderlyingFilterListChecker(nonInterpolableList));
+    }
+
+    bool isValid(const InterpolationEnvironment&, const InterpolationValue& underlying) const final
+    {
+        const NonInterpolableList& underlyingNonInterpolableList = toNonInterpolableList(*underlying.nonInterpolableValue);
+        if (m_nonInterpolableList->length() != underlyingNonInterpolableList.length())
+            return false;
+        for (size_t i = 0; i < m_nonInterpolableList->length(); i++) {
+            if (!FilterInterpolationFunctions::filtersAreCompatible(*m_nonInterpolableList->get(i), *underlyingNonInterpolableList.get(i)))
+                return false;
+        }
+        return true;
+    }
+
+private:
+    UnderlyingFilterListChecker(PassRefPtr<NonInterpolableList> nonInterpolableList)
+        : m_nonInterpolableList(nonInterpolableList)
+    { }
+
+    RefPtr<NonInterpolableList> m_nonInterpolableList;
+};
+
+class InheritedFilterListChecker : public InterpolationType::ConversionChecker {
+public:
+    static PassOwnPtr<InheritedFilterListChecker> create(CSSPropertyID property, const FilterOperations& filterOperations)
+    {
+        return adoptPtr(new InheritedFilterListChecker(property, filterOperations));
+    }
+
+    bool isValid(const InterpolationEnvironment& environment, const InterpolationValue&) const final
+    {
+        const FilterOperations& filterOperations = m_filterOperationsWrapper->operations();
+        return filterOperations == FilterListPropertyFunctions::getFilterList(m_property, *environment.state().parentStyle());
+    }
+
+private:
+    InheritedFilterListChecker(CSSPropertyID property, const FilterOperations& filterOperations)
+        : m_property(property)
+        , m_filterOperationsWrapper(FilterOperationsWrapper::create(filterOperations))
+    { }
+
+    const CSSPropertyID m_property;
+    Persistent<FilterOperationsWrapper> m_filterOperationsWrapper;
+};
+
+InterpolationValue convertFilterList(const FilterOperations& filterOperations, double zoom)
+{
+    size_t length = filterOperations.size();
+    OwnPtr<InterpolableList> interpolableList = InterpolableList::create(length);
+    Vector<RefPtr<NonInterpolableValue>> nonInterpolableValues(length);
+    for (size_t i = 0; i < length; i++) {
+        InterpolationValue filterResult = FilterInterpolationFunctions::maybeConvertFilter(*filterOperations.operations()[i], zoom);
+        if (!filterResult)
+            return nullptr;
+        interpolableList->set(i, filterResult.interpolableValue.release());
+        nonInterpolableValues[i] = filterResult.nonInterpolableValue.release();
+    }
+    return InterpolationValue(interpolableList.release(), NonInterpolableList::create(nonInterpolableValues));
+}
+
+} // namespace
+
+InterpolationValue CSSFilterListInterpolationType::maybeConvertNeutral(const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const
+{
+    // const_cast for taking refs.
+    NonInterpolableList& nonInterpolableList = const_cast<NonInterpolableList&>(toNonInterpolableList(*underlying.nonInterpolableValue));
+    conversionCheckers.append(UnderlyingFilterListChecker::create(&nonInterpolableList));
+    return InterpolationValue(underlying.interpolableValue->cloneAndZero(), &nonInterpolableList);
+}
+
+InterpolationValue CSSFilterListInterpolationType::maybeConvertInitial(const StyleResolverState&) const
+{
+    return convertFilterList(FilterListPropertyFunctions::getInitialFilterList(cssProperty()), 1);
+}
+
+InterpolationValue CSSFilterListInterpolationType::maybeConvertInherit(const StyleResolverState& state, ConversionCheckers& conversionCheckers) const
+{
+    const FilterOperations& inheritedFilterOperations = FilterListPropertyFunctions::getFilterList(cssProperty(), *state.parentStyle());
+    conversionCheckers.append(InheritedFilterListChecker::create(cssProperty(), inheritedFilterOperations));
+    return convertFilterList(inheritedFilterOperations, state.style()->effectiveZoom());
+}
+
+InterpolationValue CSSFilterListInterpolationType::maybeConvertValue(const CSSValue& value, const StyleResolverState&, ConversionCheckers&) const
+{
+    if (value.isPrimitiveValue() && toCSSPrimitiveValue(value).getValueID() == CSSValueNone)
+        return InterpolationValue(InterpolableList::create(0), NonInterpolableList::create());
+
+    if (!value.isBaseValueList())
+        return nullptr;
+
+    const CSSValueList& list = toCSSValueList(value);
+    size_t length = list.length();
+    OwnPtr<InterpolableList> interpolableList = InterpolableList::create(length);
+    Vector<RefPtr<NonInterpolableValue>> nonInterpolableValues(length);
+    for (size_t i = 0; i < length; i++) {
+        InterpolationValue itemResult = FilterInterpolationFunctions::maybeConvertCSSFilter(*list.item(i));
+        if (!itemResult)
+            return nullptr;
+        interpolableList->set(i, itemResult.interpolableValue.release());
+        nonInterpolableValues[i] = itemResult.nonInterpolableValue.release();
+    }
+    return InterpolationValue(interpolableList.release(), NonInterpolableList::create(nonInterpolableValues));
+}
+
+InterpolationValue CSSFilterListInterpolationType::maybeConvertUnderlyingValue(const InterpolationEnvironment& environment) const
+{
+    const ComputedStyle& style = *environment.state().style();
+    return convertFilterList(FilterListPropertyFunctions::getFilterList(cssProperty(), style), style.effectiveZoom());
+}
+
+PairwiseInterpolationValue CSSFilterListInterpolationType::mergeSingleConversions(InterpolationValue&& start, InterpolationValue&& end) const
+{
+    NonInterpolableList& startNonInterpolableList = toNonInterpolableList(*start.nonInterpolableValue);
+    NonInterpolableList& endNonInterpolableList = toNonInterpolableList(*end.nonInterpolableValue);
+    size_t startLength = startNonInterpolableList.length();
+    size_t endLength = endNonInterpolableList.length();
+
+    for (size_t i = 0; i < startLength && i < endLength; i++) {
+        if (!FilterInterpolationFunctions::filtersAreCompatible(*startNonInterpolableList.get(i), *endNonInterpolableList.get(i)))
+            return nullptr;
+    }
+
+    if (startLength == endLength)
+        return PairwiseInterpolationValue(start.interpolableValue.release(), end.interpolableValue.release(), start.nonInterpolableValue.release());
+
+    // Extend the shorter InterpolableList with neutral values that are compatible with corresponding filters in the longer list.
+    InterpolationValue& shorter = startLength < endLength ? start : end;
+    InterpolationValue& longer = startLength < endLength ? end : start;
+    size_t shorterLength = toNonInterpolableList(*shorter.nonInterpolableValue).length();
+    size_t longerLength = toNonInterpolableList(*longer.nonInterpolableValue).length();
+    InterpolableList& shorterInterpolableList = toInterpolableList(*shorter.interpolableValue);
+    const NonInterpolableList& longerNonInterpolableList = toNonInterpolableList(*longer.nonInterpolableValue);
+    OwnPtr<InterpolableList> extendedInterpolableList = InterpolableList::create(longerLength);
+    for (size_t i = 0; i < longerLength; i++) {
+        if (i < shorterLength)
+            extendedInterpolableList->set(i, shorterInterpolableList.getMutable(i).release());
+        else
+            extendedInterpolableList->set(i, FilterInterpolationFunctions::createNoneValue(*longerNonInterpolableList.get(i)));
+    }
+    shorter.interpolableValue = extendedInterpolableList.release();
+
+    return PairwiseInterpolationValue(start.interpolableValue.release(), end.interpolableValue.release(), longer.nonInterpolableValue.release());
+}
+
+void CSSFilterListInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value, double interpolationFraction) const
+{
+    const NonInterpolableList& underlyingNonInterpolableList = toNonInterpolableList(*underlyingValueOwner.value().nonInterpolableValue);
+    const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*value.nonInterpolableValue);
+    size_t underlyingLength = underlyingNonInterpolableList.length();
+    size_t length = nonInterpolableList.length();
+
+    for (size_t i = 0; i < underlyingLength && i < length; i++) {
+        if (!FilterInterpolationFunctions::filtersAreCompatible(*underlyingNonInterpolableList.get(i), *nonInterpolableList.get(i))) {
+            underlyingValueOwner.set(*this, value);
+            return;
+        }
+    }
+
+    InterpolableList& underlyingInterpolableList = toInterpolableList(*underlyingValueOwner.mutableValue().interpolableValue);
+    const InterpolableList& interpolableList = toInterpolableList(*value.interpolableValue);
+    ASSERT(underlyingLength == underlyingInterpolableList.length());
+    ASSERT(length == interpolableList.length());
+
+    for (size_t i = 0; i < length && i < underlyingLength; i++)
+        underlyingInterpolableList.getMutable(i)->scaleAndAdd(underlyingFraction, *interpolableList.get(i));
+
+    if (length <= underlyingLength)
+        return;
+
+    OwnPtr<InterpolableList> extendedInterpolableList = InterpolableList::create(length);
+    for (size_t i = 0; i < length; i++) {
+        if (i < underlyingLength)
+            extendedInterpolableList->set(i, underlyingInterpolableList.getMutable(i).release());
+        else
+            extendedInterpolableList->set(i, interpolableList.get(i)->clone());
+    }
+    underlyingValueOwner.mutableValue().interpolableValue = extendedInterpolableList.release();
+    // const_cast to take a ref.
+    underlyingValueOwner.mutableValue().nonInterpolableValue = const_cast<NonInterpolableValue*>(value.nonInterpolableValue.get());
+}
+
+void CSSFilterListInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const
+{
+    const InterpolableList& interpolableList = toInterpolableList(interpolableValue);
+    const NonInterpolableList& nonInterpolableList = toNonInterpolableList(*nonInterpolableValue);
+    size_t length = interpolableList.length();
+    ASSERT(length == nonInterpolableList.length());
+
+    FilterOperations filterOperations;
+    filterOperations.operations().reserveCapacity(length);
+    for (size_t i = 0; i < length; i++)
+        filterOperations.operations().append(FilterInterpolationFunctions::createFilter(*interpolableList.get(i), *nonInterpolableList.get(i), environment.state()));
+    FilterListPropertyFunctions::setFilterList(cssProperty(), *environment.state().style(), std::move(filterOperations));
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.h b/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.h
new file mode 100644
index 0000000..ccb2010
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/CSSFilterListInterpolationType.h
@@ -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.
+
+#ifndef CSSFilterListInterpolationType_h
+#define CSSFilterListInterpolationType_h
+
+#include "core/animation/CSSInterpolationType.h"
+
+namespace blink {
+
+class CSSFilterListInterpolationType : public CSSInterpolationType {
+public:
+    CSSFilterListInterpolationType(CSSPropertyID property)
+        : CSSInterpolationType(property)
+    { }
+
+    InterpolationValue maybeConvertUnderlyingValue(const InterpolationEnvironment&) const final;
+    PairwiseInterpolationValue mergeSingleConversions(InterpolationValue&& start, InterpolationValue&& end) const final;
+    void composite(UnderlyingValueOwner&, double underlyingFraction, const InterpolationValue&, double interpolationFraction) const final;
+    void apply(const InterpolableValue&, const NonInterpolableValue*, InterpolationEnvironment&) const final;
+
+private:
+    InterpolationValue maybeConvertNeutral(const InterpolationValue& underlying, ConversionCheckers&) const final;
+    InterpolationValue maybeConvertInitial(const StyleResolverState&) const final;
+    InterpolationValue maybeConvertInherit(const StyleResolverState&, ConversionCheckers&) const final;
+    InterpolationValue maybeConvertValue(const CSSValue&, const StyleResolverState&, ConversionCheckers&) const final;
+
+};
+
+} // namespace blink
+
+#endif // CSSFilterListInterpolationType_h
diff --git a/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp
new file mode 100644
index 0000000..18029e9
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.cpp
@@ -0,0 +1,269 @@
+// 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/animation/FilterInterpolationFunctions.h"
+
+#include "core/animation/CSSLengthInterpolationType.h"
+#include "core/animation/ShadowInterpolationFunctions.h"
+#include "core/css/CSSFunctionValue.h"
+#include "core/css/CSSPrimitiveValue.h"
+#include "core/css/resolver/FilterOperationResolver.h"
+#include "core/css/resolver/StyleResolverState.h"
+#include "core/style/ShadowData.h"
+#include "platform/graphics/filters/FilterOperations.h"
+
+namespace blink {
+
+class FilterNonInterpolableValue : public NonInterpolableValue {
+public:
+    static PassRefPtr<FilterNonInterpolableValue> create(FilterOperation::OperationType type, PassRefPtr<NonInterpolableValue> typeNonInterpolableValue)
+    {
+        return adoptRef(new FilterNonInterpolableValue(type, typeNonInterpolableValue));
+    }
+
+    FilterOperation::OperationType type() const { return m_type; }
+    const NonInterpolableValue* typeNonInterpolableValue() const { return m_typeNonInterpolableValue.get(); }
+
+    DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
+
+private:
+    FilterNonInterpolableValue(FilterOperation::OperationType type, PassRefPtr<NonInterpolableValue> typeNonInterpolableValue)
+        : m_type(type)
+        , m_typeNonInterpolableValue(typeNonInterpolableValue)
+    { }
+
+    const FilterOperation::OperationType m_type;
+    RefPtr<NonInterpolableValue> m_typeNonInterpolableValue;
+};
+
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE(FilterNonInterpolableValue);
+DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(FilterNonInterpolableValue);
+
+namespace {
+
+double defaultParameter(FilterOperation::OperationType type)
+{
+    switch (type) {
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA:
+        return 1;
+
+    case FilterOperation::CONTRAST:
+    case FilterOperation::HUE_ROTATE:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+        return 0;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+double clampParameter(double value, FilterOperation::OperationType type)
+{
+    switch (type) {
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::SATURATE:
+        return clampTo<double>(value, 0);
+
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SEPIA:
+        return clampTo<double>(value, 0, 1);
+
+    case FilterOperation::HUE_ROTATE:
+        return value;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return 0;
+    }
+}
+
+} // namespace
+
+InterpolationValue FilterInterpolationFunctions::maybeConvertCSSFilter(const CSSValue& value)
+{
+    const CSSFunctionValue& filter = toCSSFunctionValue(value);
+    ASSERT(filter.length() <= 1);
+    FilterOperation::OperationType type = FilterOperationResolver::filterOperationForType(filter.functionType());
+    InterpolationValue result = nullptr;
+
+    switch (type) {
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA: {
+        double amount = defaultParameter(type);
+        if (filter.length() == 1) {
+            const CSSPrimitiveValue& firstValue = toCSSPrimitiveValue(*filter.item(0));
+            amount = firstValue.getDoubleValue();
+            if (firstValue.isPercentage())
+                amount /= 100;
+        }
+        result.interpolableValue = InterpolableNumber::create(amount);
+        break;
+    }
+
+    case FilterOperation::HUE_ROTATE: {
+        double angle = defaultParameter(type);
+        if (filter.length() == 1)
+            angle = toCSSPrimitiveValue(*filter.item(0)).computeDegrees();
+        result.interpolableValue = InterpolableNumber::create(angle);
+        break;
+    }
+
+    case FilterOperation::BLUR: {
+        if (filter.length() == 0)
+            result.interpolableValue = CSSLengthInterpolationType::createNeutralInterpolableValue();
+        else
+            result = CSSLengthInterpolationType::maybeConvertCSSValue(*filter.item(0));
+        break;
+    }
+
+    case FilterOperation::DROP_SHADOW: {
+        result = ShadowInterpolationFunctions::maybeConvertCSSValue(*filter.item(0));
+        break;
+    }
+
+    case FilterOperation::REFERENCE:
+        return nullptr;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+
+    if (!result)
+        return nullptr;
+
+    result.nonInterpolableValue = FilterNonInterpolableValue::create(type, result.nonInterpolableValue.release());
+    return result;
+}
+
+InterpolationValue FilterInterpolationFunctions::maybeConvertFilter(const FilterOperation& filter, double zoom)
+{
+    InterpolationValue result = nullptr;
+
+    switch (filter.type()) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::HUE_ROTATE:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA:
+        result.interpolableValue = InterpolableNumber::create(toBasicColorMatrixFilterOperation(filter).amount());
+        break;
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+        result.interpolableValue = InterpolableNumber::create(toBasicComponentTransferFilterOperation(filter).amount());
+        break;
+
+    case FilterOperation::BLUR:
+        result = CSSLengthInterpolationType::maybeConvertLength(toBlurFilterOperation(filter).stdDeviation(), zoom);
+        break;
+
+    case FilterOperation::DROP_SHADOW: {
+        const DropShadowFilterOperation& blurFilter = toDropShadowFilterOperation(filter);
+        ShadowData shadowData(blurFilter.location(), blurFilter.stdDeviation(), 0, Normal, blurFilter.getColor());
+        result = ShadowInterpolationFunctions::convertShadowData(shadowData, zoom);
+        break;
+    }
+
+    case FilterOperation::REFERENCE:
+        return nullptr;
+
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+
+    if (!result)
+        return nullptr;
+
+    result.nonInterpolableValue = FilterNonInterpolableValue::create(filter.type(), result.nonInterpolableValue.release());
+    return result;
+}
+
+PassOwnPtr<InterpolableValue> FilterInterpolationFunctions::createNoneValue(const NonInterpolableValue& untypedNonInterpolableValue)
+{
+    switch (toFilterNonInterpolableValue(untypedNonInterpolableValue).type()) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::SEPIA:
+    case FilterOperation::HUE_ROTATE:
+        return InterpolableNumber::create(0);
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SATURATE:
+        return InterpolableNumber::create(1);
+
+    case FilterOperation::BLUR:
+        return CSSLengthInterpolationType::createNeutralInterpolableValue();
+
+    case FilterOperation::DROP_SHADOW:
+        return ShadowInterpolationFunctions::createNeutralInterpolableValue();
+
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+}
+
+bool FilterInterpolationFunctions::filtersAreCompatible(const NonInterpolableValue& a, const NonInterpolableValue& b)
+{
+    return toFilterNonInterpolableValue(a).type() == toFilterNonInterpolableValue(b).type();
+}
+
+FilterOperation* FilterInterpolationFunctions::createFilter(const InterpolableValue& interpolableValue, const NonInterpolableValue& untypedNonInterpolableValue, const StyleResolverState& state)
+{
+    const FilterNonInterpolableValue& nonInterpolableValue = toFilterNonInterpolableValue(untypedNonInterpolableValue);
+    FilterOperation::OperationType type = nonInterpolableValue.type();
+
+    switch (type) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::HUE_ROTATE:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA: {
+        double value = clampParameter(toInterpolableNumber(interpolableValue).value(), type);
+        return BasicColorMatrixFilterOperation::create(value, type);
+    }
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY: {
+        double value = clampParameter(toInterpolableNumber(interpolableValue).value(), type);
+        return BasicComponentTransferFilterOperation::create(value, type);
+    }
+
+    case FilterOperation::BLUR: {
+        Length stdDeviation = CSSLengthInterpolationType::resolveInterpolableLength(interpolableValue, nonInterpolableValue.typeNonInterpolableValue(), state.cssToLengthConversionData(), ValueRangeNonNegative);
+        return BlurFilterOperation::create(stdDeviation);
+    }
+
+    case FilterOperation::DROP_SHADOW: {
+        ShadowData shadowData = ShadowInterpolationFunctions::createShadowData(interpolableValue, nonInterpolableValue.typeNonInterpolableValue(), state);
+        Color color = shadowData.color().isCurrentColor() ? Color::black : shadowData.color().getColor();
+        return DropShadowFilterOperation::create(IntPoint(shadowData.x(), shadowData.y()), shadowData.blur(), color);
+    }
+
+    default:
+        ASSERT_NOT_REACHED();
+        return nullptr;
+    }
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.h
new file mode 100644
index 0000000..0f9c6c96
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/FilterInterpolationFunctions.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 FilterInterpolationFunctions_h
+#define FilterInterpolationFunctions_h
+
+#include "core/animation/InterpolationValue.h"
+#include "platform/heap/Handle.h"
+
+namespace blink {
+
+class FilterOperation;
+class CSSValue;
+class StyleResolverState;
+
+namespace FilterInterpolationFunctions {
+
+InterpolationValue maybeConvertCSSFilter(const CSSValue&);
+InterpolationValue maybeConvertFilter(const FilterOperation&, double zoom);
+PassOwnPtr<InterpolableValue> createNoneValue(const NonInterpolableValue&);
+bool filtersAreCompatible(const NonInterpolableValue&, const NonInterpolableValue&);
+FilterOperation* createFilter(const InterpolableValue&, const NonInterpolableValue&, const StyleResolverState&);
+
+} // namespace FilterInterpolationFunctions
+
+} // namespace blink
+
+#endif // FilterInterpolationFunctions_h
diff --git a/third_party/WebKit/Source/core/animation/FilterListPropertyFunctions.h b/third_party/WebKit/Source/core/animation/FilterListPropertyFunctions.h
new file mode 100644
index 0000000..a5c61e8a
--- /dev/null
+++ b/third_party/WebKit/Source/core/animation/FilterListPropertyFunctions.h
@@ -0,0 +1,53 @@
+// 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 FilterListPropertyFunctions_h
+#define FilterListPropertyFunctions_h
+
+#include "core/CSSPropertyNames.h"
+#include "core/style/ComputedStyle.h"
+#include "wtf/Allocator.h"
+
+namespace blink {
+
+class FilterListPropertyFunctions {
+    STATIC_ONLY(FilterListPropertyFunctions);
+public:
+    static const FilterOperations& getInitialFilterList(CSSPropertyID property)
+    {
+        return getFilterList(property, ComputedStyle::initialStyle());
+    }
+
+    static const FilterOperations& getFilterList(CSSPropertyID property, const ComputedStyle& style)
+    {
+        switch (property) {
+        default:
+            ASSERT_NOT_REACHED();
+            // Fall through.
+        case CSSPropertyBackdropFilter:
+            return style.backdropFilter();
+        case CSSPropertyWebkitFilter:
+            return style.filter();
+        }
+    }
+
+    static void setFilterList(CSSPropertyID property, ComputedStyle& style, const FilterOperations& filterOperations)
+    {
+        switch (property) {
+        case CSSPropertyBackdropFilter:
+            style.setBackdropFilter(filterOperations);
+            break;
+        case CSSPropertyWebkitFilter:
+            style.setFilter(filterOperations);
+            break;
+        default:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+    }
+};
+
+} // namespace blink
+
+#endif // FilterListPropertyFunctions_h
diff --git a/third_party/WebKit/Source/core/animation/ListInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/ListInterpolationFunctions.h
index 7912364..35bae05 100644
--- a/third_party/WebKit/Source/core/animation/ListInterpolationFunctions.h
+++ b/third_party/WebKit/Source/core/animation/ListInterpolationFunctions.h
@@ -36,6 +36,10 @@
 public:
     ~NonInterpolableList() final { }
 
+    static PassRefPtr<NonInterpolableList> create()
+    {
+        return adoptRef(new NonInterpolableList());
+    }
     static PassRefPtr<NonInterpolableList> create(Vector<RefPtr<NonInterpolableValue>>& list)
     {
         return adoptRef(new NonInterpolableList(list));
@@ -49,6 +53,8 @@
     DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
 
 private:
+    NonInterpolableList()
+    { }
     NonInterpolableList(Vector<RefPtr<NonInterpolableValue>>& list)
     {
         m_list.swap(list);
diff --git a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp b/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp
index a52533c0..a197e9de 100644
--- a/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp
+++ b/third_party/WebKit/Source/core/animation/PropertyInterpolationTypesMapping.cpp
@@ -9,6 +9,7 @@
 #include "core/animation/CSSBorderImageLengthBoxInterpolationType.h"
 #include "core/animation/CSSClipInterpolationType.h"
 #include "core/animation/CSSColorInterpolationType.h"
+#include "core/animation/CSSFilterListInterpolationType.h"
 #include "core/animation/CSSFontSizeInterpolationType.h"
 #include "core/animation/CSSFontWeightInterpolationType.h"
 #include "core/animation/CSSImageInterpolationType.h"
@@ -239,6 +240,10 @@
         case CSSPropertyRotate:
             applicableTypes->append(adoptPtr(new CSSRotateInterpolationType(cssProperty)));
             break;
+        case CSSPropertyBackdropFilter:
+        case CSSPropertyWebkitFilter:
+            applicableTypes->append(adoptPtr(new CSSFilterListInterpolationType(cssProperty)));
+            break;
         default:
             // TODO(alancutter): Support all interpolable CSS properties here so we can stop falling back to the old StyleInterpolation implementation.
             if (CSSPropertyMetadata::isInterpolableProperty(cssProperty))
diff --git a/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.cpp b/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.cpp
index 8e0a789..9e19b299 100644
--- a/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.cpp
+++ b/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.cpp
@@ -120,6 +120,11 @@
     return InterpolationValue(interpolableList.release(), ShadowNonInterpolableValue::create(style));
 }
 
+PassOwnPtr<InterpolableValue> ShadowInterpolationFunctions::createNeutralInterpolableValue()
+{
+    return convertShadowData(ShadowData(FloatPoint(0, 0), 0, 0, Normal, StyleColor(Color::transparent)), 1).interpolableValue.release();
+}
+
 void ShadowInterpolationFunctions::composite(OwnPtr<InterpolableValue>& underlyingInterpolableValue, RefPtr<NonInterpolableValue>& underlyingNonInterpolableValue, double underlyingFraction, const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue)
 {
     ASSERT(nonInterpolableValuesAreCompatible(underlyingNonInterpolableValue.get(), nonInterpolableValue));
diff --git a/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.h b/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.h
index cd0a846..ceaa7fa 100644
--- a/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.h
+++ b/third_party/WebKit/Source/core/animation/ShadowInterpolationFunctions.h
@@ -18,6 +18,7 @@
 public:
     static InterpolationValue convertShadowData(const ShadowData&, double zoom);
     static InterpolationValue maybeConvertCSSValue(const CSSValue&);
+    static PassOwnPtr<InterpolableValue> createNeutralInterpolableValue();
     static bool nonInterpolableValuesAreCompatible(const NonInterpolableValue*, const NonInterpolableValue*);
     static PairwiseInterpolationValue mergeSingleConversions(InterpolationValue&& start, InterpolationValue&& end);
     static void composite(OwnPtr<InterpolableValue>&, RefPtr<NonInterpolableValue>&, double underlyingFraction, const InterpolableValue&, const NonInterpolableValue*);
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index 3969559..3515acb 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -880,6 +880,8 @@
             'animation/CSSClipInterpolationType.h',
             'animation/CSSColorInterpolationType.cpp',
             'animation/CSSColorInterpolationType.h',
+            'animation/CSSFilterListInterpolationType.cpp',
+            'animation/CSSFilterListInterpolationType.h',
             'animation/CSSFontWeightInterpolationType.cpp',
             'animation/CSSFontWeightInterpolationType.h',
             'animation/CSSFontSizeInterpolationType.cpp',
@@ -945,6 +947,9 @@
             'animation/ElementAnimation.h',
             'animation/ElementAnimations.cpp',
             'animation/ElementAnimations.h',
+            'animation/FilterListPropertyFunctions.h',
+            'animation/FilterInterpolationFunctions.cpp',
+            'animation/FilterInterpolationFunctions.h',
             'animation/ImageListPropertyFunctions.h',
             'animation/ImagePropertyFunctions.h',
             'animation/ImageSlicePropertyFunctions.h',
@@ -2234,6 +2239,8 @@
             'workers/SharedWorkerThread.h',
             'workers/Worker.cpp',
             'workers/Worker.h',
+            'workers/WorkerBackingThread.cpp',
+            'workers/WorkerBackingThread.h',
             'workers/WorkerClients.h',
             'workers/WorkerConsole.cpp',
             'workers/WorkerConsole.h',
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
index bdbf13a..2ef70ed 100644
--- a/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
+++ b/third_party/WebKit/Source/core/css/CSSFontSelector.cpp
@@ -59,10 +59,6 @@
 
 CSSFontSelector::~CSSFontSelector()
 {
-#if !ENABLE(OILPAN)
-    clearDocument();
-    FontCache::fontCache()->removeClient(this);
-#endif
 }
 
 void CSSFontSelector::registerForInvalidationCallbacks(CSSFontSelectorClient* client)
@@ -70,13 +66,6 @@
     m_clients.add(client);
 }
 
-#if !ENABLE(OILPAN)
-void CSSFontSelector::unregisterForInvalidationCallbacks(CSSFontSelectorClient* client)
-{
-    m_clients.remove(client);
-}
-#endif
-
 void CSSFontSelector::dispatchInvalidationCallbacks()
 {
     m_fontFaceCache.incrementVersion();
@@ -162,15 +151,6 @@
     return FontCache::fontCache()->isPlatformFontAvailable(fontDescription, family);
 }
 
-#if !ENABLE(OILPAN)
-void CSSFontSelector::clearDocument()
-{
-    m_fontLoader->clearDocumentAndFontSelector();
-    m_document = nullptr;
-    m_fontFaceCache.clearAll();
-}
-#endif
-
 void CSSFontSelector::updateGenericFontFamilySettings(Document& document)
 {
     if (!document.settings())
diff --git a/third_party/WebKit/Source/core/css/CSSFontSelector.h b/third_party/WebKit/Source/core/css/CSSFontSelector.h
index 6e169b2b5b..e9a12e6 100644
--- a/third_party/WebKit/Source/core/css/CSSFontSelector.h
+++ b/third_party/WebKit/Source/core/css/CSSFontSelector.h
@@ -57,19 +57,12 @@
     void willUseRange(const FontDescription&, const AtomicString& familyName, const FontDataForRangeSet&) override;
     bool isPlatformFontAvailable(const FontDescription&, const AtomicString& family);
 
-#if !ENABLE(OILPAN)
-    void clearDocument();
-#endif
-
     void fontFaceInvalidated();
 
     // FontCacheClient implementation
     void fontCacheInvalidated() override;
 
     void registerForInvalidationCallbacks(CSSFontSelectorClient*);
-#if !ENABLE(OILPAN)
-    void unregisterForInvalidationCallbacks(CSSFontSelectorClient*);
-#endif
 
     Document* document() const { return m_document; }
     FontFaceCache* fontFaceCache() { return &m_fontFaceCache; }
@@ -86,7 +79,7 @@
     void dispatchInvalidationCallbacks();
 
 private:
-    // FIXME: Oilpan: Ideally this should just be a traced Member but that will
+    // TODO(Oilpan): Ideally this should just be a traced Member but that will
     // currently leak because ComputedStyle and its data are not on the heap.
     // See crbug.com/383860 for details.
     WeakMember<Document> m_document;
diff --git a/third_party/WebKit/Source/core/css/CSSRuleList.cpp b/third_party/WebKit/Source/core/css/CSSRuleList.cpp
index 7df88a8..71eec956 100644
--- a/third_party/WebKit/Source/core/css/CSSRuleList.cpp
+++ b/third_party/WebKit/Source/core/css/CSSRuleList.cpp
@@ -25,30 +25,10 @@
 
 namespace blink {
 
-CSSRuleList::~CSSRuleList()
-{
-}
-
 StaticCSSRuleList::StaticCSSRuleList()
-#if !ENABLE(OILPAN)
-    : m_refCount(1)
-#endif
 {
 }
 
-StaticCSSRuleList::~StaticCSSRuleList()
-{
-}
-
-#if !ENABLE(OILPAN)
-void StaticCSSRuleList::deref()
-{
-    ASSERT(m_refCount);
-    if (!--m_refCount)
-        delete this;
-}
-#endif
-
 DEFINE_TRACE(StaticCSSRuleList)
 {
     visitor->trace(m_rules);
diff --git a/third_party/WebKit/Source/core/css/CSSRuleList.h b/third_party/WebKit/Source/core/css/CSSRuleList.h
index e22ee18ac..af2277d 100644
--- a/third_party/WebKit/Source/core/css/CSSRuleList.h
+++ b/third_party/WebKit/Source/core/css/CSSRuleList.h
@@ -33,16 +33,10 @@
 class CSSRule;
 class CSSStyleSheet;
 
-class CSSRuleList : public GarbageCollectedFinalized<CSSRuleList>, public ScriptWrappable {
+class CSSRuleList : public GarbageCollected<CSSRuleList>, public ScriptWrappable {
     DEFINE_WRAPPERTYPEINFO();
     WTF_MAKE_NONCOPYABLE(CSSRuleList);
 public:
-    virtual ~CSSRuleList();
-
-#if !ENABLE(OILPAN)
-    virtual void ref() = 0;
-    virtual void deref() = 0;
-#endif
 
     virtual unsigned length() const = 0;
     virtual CSSRule* item(unsigned index) const = 0;
@@ -62,11 +56,6 @@
         return new StaticCSSRuleList();
     }
 
-#if !ENABLE(OILPAN)
-    void ref() override { ++m_refCount; }
-    void deref() override;
-#endif
-
     HeapVector<Member<CSSRule>>& rules() { return m_rules; }
 
     CSSStyleSheet* styleSheet() const override { return 0; }
@@ -75,15 +64,11 @@
 
 private:
     StaticCSSRuleList();
-    ~StaticCSSRuleList() override;
 
     unsigned length() const override { return m_rules.size(); }
     CSSRule* item(unsigned index) const override { return index < m_rules.size() ? m_rules[index].get() : nullptr; }
 
     HeapVector<Member<CSSRule>> m_rules;
-#if !ENABLE(OILPAN)
-    unsigned m_refCount;
-#endif
 };
 
 template <class Rule>
@@ -94,11 +79,6 @@
         return new LiveCSSRuleList(rule);
     }
 
-#if !ENABLE(OILPAN)
-    void ref() override { m_rule->ref(); }
-    void deref() override { m_rule->deref(); }
-#endif
-
     DEFINE_INLINE_VIRTUAL_TRACE()
     {
         visitor->trace(m_rule);
diff --git a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
index bf1a5ab..31269cdb 100644
--- a/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
+++ b/third_party/WebKit/Source/core/css/CSSSelectorList.cpp
@@ -27,7 +27,7 @@
 #include "core/css/CSSSelectorList.h"
 
 #include "core/css/parser/CSSParserSelector.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/StringBuilder.h"
 
 namespace {
diff --git a/third_party/WebKit/Source/core/css/CSSStyleRule.cpp b/third_party/WebKit/Source/core/css/CSSStyleRule.cpp
index 701e281c..de1fe3a 100644
--- a/third_party/WebKit/Source/core/css/CSSStyleRule.cpp
+++ b/third_party/WebKit/Source/core/css/CSSStyleRule.cpp
@@ -47,16 +47,6 @@
 
 CSSStyleRule::~CSSStyleRule()
 {
-#if !ENABLE(OILPAN)
-    if (m_propertiesCSSOMWrapper)
-        m_propertiesCSSOMWrapper->clearParentRule();
-#endif
-    if (hasCachedSelectorText()) {
-#if !ENABLE(OILPAN)
-        selectorTextCache().remove(this);
-#endif
-        setHasCachedSelectorText(false);
-    }
 }
 
 CSSStyleDeclaration* CSSStyleRule::style() const
diff --git a/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp b/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp
index a811fe1e..5ea93ee 100644
--- a/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp
+++ b/third_party/WebKit/Source/core/css/CSSStyleSheet.cpp
@@ -60,11 +60,6 @@
 private:
     StyleSheetCSSRuleList(CSSStyleSheet* sheet) : m_styleSheet(sheet) { }
 
-#if !ENABLE(OILPAN)
-    void ref() override { m_styleSheet->ref(); }
-    void deref() override { m_styleSheet->deref(); }
-#endif
-
     unsigned length() const override { return m_styleSheet->length(); }
     CSSRule* item(unsigned index) const override { return m_styleSheet->item(index); }
 
@@ -77,10 +72,8 @@
 static bool isAcceptableCSSStyleSheetParent(Node* parentNode)
 {
     // Only these nodes can be parents of StyleSheets, and they need to call
-    // clearOwnerNode() when moved out of document.
-    // Destruction of the style sheet counts as being "moved out of the
-    // document", but only in the non-oilpan version of blink. I.e. don't call
-    // clearOwnerNode() in the owner's destructor in oilpan.
+    // clearOwnerNode() when moved out of document. Note that destructor of
+    // the nodes don't call clearOwnerNode() with Oilpan.
     return !parentNode
         || parentNode->isDocumentNode()
         || isHTMLLinkElement(*parentNode)
@@ -140,24 +133,6 @@
 
 CSSStyleSheet::~CSSStyleSheet()
 {
-    // With oilpan the parent style sheet pointer is strong and the sheet and
-    // its RuleCSSOMWrappers die together and we don't need to clear them here.
-    // Also with oilpan the StyleSheetContents client pointers are weak and
-    // therefore do not need to be cleared here.
-#if !ENABLE(OILPAN)
-    // For style rules outside the document, .parentStyleSheet can become null even if the style rule
-    // is still observable from JavaScript. This matches the behavior of .parentNode for nodes, but
-    // it's not ideal because it makes the CSSOM's behavior depend on the timing of garbage collection.
-    for (unsigned i = 0; i < m_childRuleCSSOMWrappers.size(); ++i) {
-        if (m_childRuleCSSOMWrappers[i])
-            m_childRuleCSSOMWrappers[i]->setParentStyleSheet(0);
-    }
-
-    if (m_mediaCSSOMWrapper)
-        m_mediaCSSOMWrapper->clearParentStyleSheet();
-
-    m_contents->unregisterClient(this);
-#endif
 }
 
 void CSSStyleSheet::willMutateRules()
diff --git a/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.cpp b/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.cpp
index 3ac4257f..d23a74c 100644
--- a/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.cpp
+++ b/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.cpp
@@ -126,18 +126,6 @@
 
 } // namespace
 
-#if !ENABLE(OILPAN)
-void PropertySetCSSStyleDeclaration::ref()
-{
-    m_propertySet->ref();
-}
-
-void PropertySetCSSStyleDeclaration::deref()
-{
-    m_propertySet->deref();
-}
-#endif
-
 DEFINE_TRACE(PropertySetCSSStyleDeclaration)
 {
     visitor->trace(m_propertySet);
@@ -320,37 +308,14 @@
 
 StyleRuleCSSStyleDeclaration::StyleRuleCSSStyleDeclaration(MutableStylePropertySet& propertySetArg, CSSRule* parentRule)
     : PropertySetCSSStyleDeclaration(propertySetArg)
-#if !ENABLE(OILPAN)
-    , m_refCount(1)
-#endif
     , m_parentRule(parentRule)
 {
-#if !ENABLE(OILPAN)
-    m_propertySet->ref();
-#endif
 }
 
 StyleRuleCSSStyleDeclaration::~StyleRuleCSSStyleDeclaration()
 {
-#if !ENABLE(OILPAN)
-    m_propertySet->deref();
-#endif
 }
 
-#if !ENABLE(OILPAN)
-void StyleRuleCSSStyleDeclaration::ref()
-{
-    ++m_refCount;
-}
-
-void StyleRuleCSSStyleDeclaration::deref()
-{
-    ASSERT(m_refCount);
-    if (!--m_refCount)
-        delete this;
-}
-#endif
-
 void StyleRuleCSSStyleDeclaration::willMutate()
 {
     if (m_parentRule && m_parentRule->parentStyleSheet())
@@ -371,13 +336,7 @@
 
 void StyleRuleCSSStyleDeclaration::reattach(MutableStylePropertySet& propertySet)
 {
-#if !ENABLE(OILPAN)
-    m_propertySet->deref();
-#endif
     m_propertySet = &propertySet;
-#if !ENABLE(OILPAN)
-    m_propertySet->ref();
-#endif
 }
 
 DEFINE_TRACE(StyleRuleCSSStyleDeclaration)
@@ -410,18 +369,6 @@
     return m_parentElement ? &m_parentElement->document().elementSheet() : nullptr;
 }
 
-#if !ENABLE(OILPAN)
-void InlineCSSStyleDeclaration::ref()
-{
-    m_parentElement->ref();
-}
-
-void InlineCSSStyleDeclaration::deref()
-{
-    m_parentElement->deref();
-}
-#endif
-
 DEFINE_TRACE(InlineCSSStyleDeclaration)
 {
     visitor->trace(m_parentElement);
diff --git a/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.h b/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.h
index 2157d74..e2ef4e86 100644
--- a/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.h
+++ b/third_party/WebKit/Source/core/css/PropertySetCSSStyleDeclaration.h
@@ -77,11 +77,6 @@
 public:
     PropertySetCSSStyleDeclaration(MutableStylePropertySet& propertySet) : m_propertySet(&propertySet) { }
 
-#if !ENABLE(OILPAN)
-    void ref() override;
-    void deref() override;
-#endif
-
     DECLARE_VIRTUAL_TRACE();
 
 protected:
@@ -97,13 +92,6 @@
         return new StyleRuleCSSStyleDeclaration(propertySet, parentRule);
     }
 
-#if !ENABLE(OILPAN)
-    void clearParentRule() { m_parentRule = nullptr; }
-
-    void ref() override;
-    void deref() override;
-#endif
-
     void reattach(MutableStylePropertySet&);
 
     DECLARE_VIRTUAL_TRACE();
@@ -119,9 +107,6 @@
     void willMutate() override;
     void didMutate(MutationType) override;
 
-#if !ENABLE(OILPAN)
-    unsigned m_refCount;
-#endif
     Member<CSSRule> m_parentRule;
 };
 
@@ -136,10 +121,6 @@
 
 private:
     MutableStylePropertySet& propertySet() const override;
-#if !ENABLE(OILPAN)
-    void ref() override;
-    void deref() override;
-#endif
     CSSStyleSheet* parentStyleSheet() const override;
     Element* parentElement() const override { return m_parentElement; }
 
diff --git a/third_party/WebKit/Source/core/css/StylePropertySet.cpp b/third_party/WebKit/Source/core/css/StylePropertySet.cpp
index cb98e5ff..6cf1349 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySet.cpp
+++ b/third_party/WebKit/Source/core/css/StylePropertySet.cpp
@@ -81,22 +81,11 @@
     for (unsigned i = 0; i < m_arraySize; ++i) {
         metadataArray[i] = properties[i].metadata();
         valueArray[i] = properties[i].value();
-#if !ENABLE(OILPAN)
-        valueArray[i]->ref();
-#endif
     }
 }
 
 ImmutableStylePropertySet::~ImmutableStylePropertySet()
 {
-#if !ENABLE(OILPAN)
-    Member<CSSValue>* valueArray = const_cast<Member<CSSValue>*>(this->valueArray());
-    for (unsigned i = 0; i < m_arraySize; ++i) {
-        // Checking for nullptr here is a workaround to prevent crashing.  http://crbug.com/449032
-        if (valueArray[i])
-            valueArray[i]->deref();
-    }
-#endif
 }
 
 // Convert property into an uint16_t for comparison with metadata's m_propertyID to avoid
@@ -202,7 +191,6 @@
         toImmutableStylePropertySet(this)->traceAfterDispatch(visitor);
 }
 
-#if ENABLE(OILPAN)
 void StylePropertySet::finalizeGarbageCollectedObject()
 {
     if (m_isMutable)
@@ -210,7 +198,6 @@
     else
         toImmutableStylePropertySet(this)->~ImmutableStylePropertySet();
 }
-#endif
 
 bool MutableStylePropertySet::removeShorthandProperty(CSSPropertyID propertyID)
 {
diff --git a/third_party/WebKit/Source/core/css/StylePropertySet.h b/third_party/WebKit/Source/core/css/StylePropertySet.h
index 6fd4c60c..147bd60 100644
--- a/third_party/WebKit/Source/core/css/StylePropertySet.h
+++ b/third_party/WebKit/Source/core/css/StylePropertySet.h
@@ -45,16 +45,7 @@
     friend class PropertyReference;
 public:
 
-#if ENABLE(OILPAN)
-    // When oilpan is enabled override the finalize method to dispatch to the subclasses'
-    // destructor. This can be removed once the MutableStylePropertySet's OwnPtr is moved
-    // to the heap.
     void finalizeGarbageCollectedObject();
-#else
-    // Override RefCounted's deref() to ensure operator delete is called on
-    // the appropriate subclass type.
-    void deref();
-#endif
 
     class PropertyReference {
         STACK_ALLOCATED();
@@ -291,19 +282,6 @@
     return !propertyCount();
 }
 
-#if !ENABLE(OILPAN)
-inline void StylePropertySet::deref()
-{
-    if (!derefBase())
-        return;
-
-    if (m_isMutable)
-        delete toMutableStylePropertySet(this);
-    else
-        delete toImmutableStylePropertySet(this);
-}
-#endif // !ENABLE(OILPAN)
-
 template<typename T>
 inline int StylePropertySet::findPropertyIndex(T property) const
 {
diff --git a/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp b/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
index 5532fb08..592724c 100644
--- a/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
+++ b/third_party/WebKit/Source/core/css/parser/CSSTokenizerTest.cpp
@@ -7,7 +7,7 @@
 #include "core/css/parser/CSSParserTokenRange.h"
 #include "core/css/parser/MediaQueryBlockWatcher.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
index 2ade6a5..0e3c2cb5 100644
--- a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
+++ b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.cpp
@@ -39,7 +39,7 @@
 
 namespace blink {
 
-static FilterOperation::OperationType filterOperationForType(CSSValueID type)
+FilterOperation::OperationType FilterOperationResolver::filterOperationForType(CSSValueID type)
 {
     switch (type) {
     case CSSValueUrl:
diff --git a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
index c76fd68..182ca395 100644
--- a/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
+++ b/third_party/WebKit/Source/core/css/resolver/FilterOperationResolver.h
@@ -22,6 +22,7 @@
 #ifndef FilterOperationResolver_h
 #define FilterOperationResolver_h
 
+#include "core/CSSValueKeywords.h"
 #include "platform/graphics/filters/FilterOperations.h"
 #include "platform/heap/Handle.h"
 
@@ -33,6 +34,7 @@
 class FilterOperationResolver {
     STATIC_ONLY(FilterOperationResolver);
 public:
+    static FilterOperation::OperationType filterOperationForType(CSSValueID);
     static FilterOperations createFilterOperations(StyleResolverState&, const CSSValue&);
 };
 
diff --git a/third_party/WebKit/Source/core/dom/Node.cpp b/third_party/WebKit/Source/core/dom/Node.cpp
index a404510..0066cfd6 100644
--- a/third_party/WebKit/Source/core/dom/Node.cpp
+++ b/third_party/WebKit/Source/core/dom/Node.cpp
@@ -92,9 +92,9 @@
 #include "platform/TraceEvent.h"
 #include "platform/TracedValue.h"
 #include "wtf/HashSet.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/Vector.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/StringBuilder.h"
 
@@ -1542,6 +1542,38 @@
     return nodeName();
 }
 
+static void dumpAttributeDesc(const Node& node, const QualifiedName& name, std::ostream& ostream)
+{
+    if (!node.isElementNode())
+        return;
+    const AtomicString& value = toElement(node).getAttribute(name);
+    if (value.isEmpty())
+        return;
+    ostream << ' ' << name.toString().utf8().data() << '=' << value;
+}
+
+// |std::ostream| version of |Node::showNode|
+std::ostream& operator<<(std::ostream& ostream, const Node& node)
+{
+    // We avoid to print "" by utf8().data().
+    ostream << node.nodeName().utf8().data();
+    if (node.isTextNode())
+        return ostream << " " << node.nodeValue();
+    dumpAttributeDesc(node, HTMLNames::idAttr, ostream);
+    dumpAttributeDesc(node, HTMLNames::classAttr, ostream);
+    dumpAttributeDesc(node, HTMLNames::styleAttr, ostream);
+    return ostream;
+}
+
+std::ostream& operator<<(std::ostream& ostream, const Node* node)
+{
+    if (!node)
+        return ostream << "null";
+    return ostream << *node;
+}
+
+#ifndef NDEBUG
+
 static void appendAttributeDesc(const Node* node, StringBuilder& stringBuilder, const QualifiedName& name, const char* attrDesc)
 {
     if (!node->isElementNode())
@@ -1557,28 +1589,6 @@
     stringBuilder.appendLiteral("\"");
 }
 
-// |std::ostream| version of |Node::showNode|
-std::ostream& operator<<(std::ostream& ostream, const Node& node)
-{
-    ostream << node.nodeName();
-    if (node.isTextNode())
-        return ostream << " " << node.nodeValue();
-    StringBuilder attrs;
-    appendAttributeDesc(&node, attrs, HTMLNames::idAttr, " ID");
-    appendAttributeDesc(&node, attrs, HTMLNames::classAttr, " CLASS");
-    appendAttributeDesc(&node, attrs, HTMLNames::styleAttr, " STYLE");
-    return ostream << attrs.toString();
-}
-
-std::ostream& operator<<(std::ostream& ostream, const Node* node)
-{
-    if (!node)
-        return ostream << "null";
-    return ostream << *node;
-}
-
-#ifndef NDEBUG
-
 void Node::showNode(const char* prefix) const
 {
     if (!prefix)
diff --git a/third_party/WebKit/Source/core/dom/PendingScript.cpp b/third_party/WebKit/Source/core/dom/PendingScript.cpp
index 6c8c7da4..58e04a5 100644
--- a/third_party/WebKit/Source/core/dom/PendingScript.cpp
+++ b/third_party/WebKit/Source/core/dom/PendingScript.cpp
@@ -47,9 +47,7 @@
     , m_client(nullptr)
 {
     setScriptResource(resource);
-#if ENABLE(OILPAN)
     ThreadState::current()->registerPreFinalizer(this);
-#endif
 }
 
 PendingScript::~PendingScript()
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
index 1a3ed59..3b0eb121 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunner.cpp
@@ -41,10 +41,6 @@
     , m_taskRunner(Platform::current()->currentThread()->scheduler()->loadingTaskRunner())
     , m_numberOfInOrderScriptsWithPendingNotification(0)
     , m_isSuspended(false)
-#if !ENABLE(OILPAN)
-    , m_isDisposed(false)
-    , m_weakPointerFactoryForTasks(this)
-#endif
 {
     DCHECK(document);
 #ifndef NDEBUG
@@ -54,33 +50,8 @@
 
 ScriptRunner::~ScriptRunner()
 {
-#if !ENABLE(OILPAN)
-    dispose();
-#endif
 }
 
-#if !ENABLE(OILPAN)
-void ScriptRunner::dispose()
-{
-    // Make sure that ScriptLoaders don't keep their PendingScripts alive.
-    for (ScriptLoader* scriptLoader : m_pendingInOrderScripts)
-        scriptLoader->detach();
-    for (ScriptLoader* scriptLoader : m_pendingAsyncScripts)
-        scriptLoader->detach();
-    for (ScriptLoader* scriptLoader : m_inOrderScriptsToExecuteSoon)
-        scriptLoader->detach();
-    for (ScriptLoader* scriptLoader : m_asyncScriptsToExecuteSoon)
-        scriptLoader->detach();
-
-    m_pendingInOrderScripts.clear();
-    m_pendingAsyncScripts.clear();
-    m_inOrderScriptsToExecuteSoon.clear();
-    m_asyncScriptsToExecuteSoon.clear();
-    m_isDisposed = true;
-    m_numberOfInOrderScriptsWithPendingNotification = 0;
-}
-#endif
-
 void ScriptRunner::queueScriptForExecution(ScriptLoader* scriptLoader, ExecutionType executionType)
 {
     DCHECK(scriptLoader);
@@ -99,11 +70,7 @@
 
 void ScriptRunner::postTask(const WebTraceLocation& webTraceLocation)
 {
-#if !ENABLE(OILPAN)
-    m_taskRunner->postTask(webTraceLocation, bind(&ScriptRunner::executeTask, m_weakPointerFactoryForTasks.createWeakPtr()));
-#else
     m_taskRunner->postTask(webTraceLocation, bind(&ScriptRunner::executeTask, WeakPersistentThisPointer<ScriptRunner>(this)));
-#endif
 }
 
 void ScriptRunner::suspend()
@@ -190,21 +157,12 @@
         // where the ScriptLoader is associated with the wrong ScriptRunner
         // (otherwise we'd cause a use-after-free in ~ScriptRunner when it tries
         // to detach).
-        bool foundLoader = m_pendingAsyncScripts.contains(scriptLoader);
-#if !ENABLE(OILPAN)
-        // If the ScriptRunner has been disposed of, no pending scripts remain.
-        foundLoader = foundLoader || m_isDisposed;
-#endif
-        SECURITY_CHECK(foundLoader);
+        SECURITY_CHECK(m_pendingAsyncScripts.contains(scriptLoader));
         m_pendingAsyncScripts.remove(scriptLoader);
         break;
     }
     case IN_ORDER_EXECUTION:
-        bool foundLoader = removePendingInOrderScript(scriptLoader);
-#if !ENABLE(OILPAN)
-        foundLoader = foundLoader || m_isDisposed;
-#endif
-        SECURITY_CHECK(foundLoader);
+        SECURITY_CHECK(removePendingInOrderScript(scriptLoader));
         scheduleReadyInOrderScripts();
         break;
     }
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunner.h b/third_party/WebKit/Source/core/dom/ScriptRunner.h
index 234330b..fb0bfd8 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunner.h
+++ b/third_party/WebKit/Source/core/dom/ScriptRunner.h
@@ -47,9 +47,6 @@
         return new ScriptRunner(document);
     }
     ~ScriptRunner();
-#if !ENABLE(OILPAN)
-    void dispose();
-#endif
 
     enum ExecutionType { ASYNC_EXECUTION, IN_ORDER_EXECUTION };
     void queueScriptForExecution(ScriptLoader*, ExecutionType);
@@ -95,11 +92,6 @@
 #ifndef NDEBUG
     bool m_hasEverBeenSuspended;
 #endif
-
-#if !ENABLE(OILPAN)
-    bool m_isDisposed;
-    WeakPtrFactory<ScriptRunner> m_weakPointerFactoryForTasks;
-#endif
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
index 01047f0..38565aae 100644
--- a/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
+++ b/third_party/WebKit/Source/core/dom/ScriptRunnerTest.cpp
@@ -437,9 +437,7 @@
 
     m_scriptRunner.release();
 
-#if ENABLE(OILPAN)
     Heap::collectAllGarbage();
-#endif
 
     // m_scriptRunner is gone. We need to make sure that ScriptRunner::Task do not access dead object.
     EXPECT_CALL(*scriptLoader1, execute()).Times(0);
diff --git a/third_party/WebKit/Source/core/editing/state_machines/BackwardGraphemeBoundaryStateMachineTest.cpp b/third_party/WebKit/Source/core/editing/state_machines/BackwardGraphemeBoundaryStateMachineTest.cpp
index 4c8e560..fab3768 100644
--- a/third_party/WebKit/Source/core/editing/state_machines/BackwardGraphemeBoundaryStateMachineTest.cpp
+++ b/third_party/WebKit/Source/core/editing/state_machines/BackwardGraphemeBoundaryStateMachineTest.cpp
@@ -5,7 +5,6 @@
 #include "core/editing/state_machines/BackwardGraphemeBoundaryStateMachine.h"
 
 #include "core/editing/state_machines/StateMachineTestUtil.h"
-#include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/text/CharacterNames.h"
 
 namespace blink {
@@ -38,7 +37,16 @@
 const UChar32 kRisS = 0x1F1F8;
 } // namespace
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, DoNothingCase)
+class BackwardGraphemeBoundaryStatemachineTest : public GraphemeStateMachineTestBase {
+protected:
+    BackwardGraphemeBoundaryStatemachineTest() = default;
+    ~BackwardGraphemeBoundaryStatemachineTest() override = default;
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(BackwardGraphemeBoundaryStatemachineTest);
+};
+
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, DoNothingCase)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
@@ -46,264 +54,264 @@
     EXPECT_EQ(0, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, BrokenSurrogatePair)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, BrokenSurrogatePair)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // [Lead]
-    EXPECT_EQ("F", processSequenceBackward(&machine, { kLead }));
+    EXPECT_EQ("F", processSequenceBackward(&machine, asCodePoints(kLead)));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail]
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { 'a', kTrail }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints('a', kTrail)));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail]
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { kTrail, kTrail }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints(kTrail, kTrail)));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail]
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { kTrail }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints(kTrail)));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, BreakImmediately_BMP)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, BreakImmediately_BMP)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // U+0000 + U+0000
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { 0, 0 }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints(0, 0)));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + 'a'
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { 'a', 'a' }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints('a', 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + 'a'
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { kEye, 'a' }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints(kEye, 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + 'a'
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { 'a' }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints('a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // Broken surrogates.
     // [Lead] + 'a'
-    EXPECT_EQ("RF", processSequenceBackward(&machine, { kLead, 'a' }));
+    EXPECT_EQ("RF", processSequenceBackward(&machine, asCodePoints(kLead, 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + 'a'
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { 'a', kTrail, 'a' }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints('a', kTrail, 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + 'a'
     EXPECT_EQ("RRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, 'a' }));
+        asCodePoints(kTrail, kTrail, 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + 'a'
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { kTrail, 'a' }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints(kTrail, 'a')));
     EXPECT_EQ(-1, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest,
+TEST_F(BackwardGraphemeBoundaryStatemachineTest,
     BreakImmediately_SupplementaryPlane)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + U+1F441
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { 'a', kEye }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints('a', kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + U+1F441
-    EXPECT_EQ("RRRF", processSequenceBackward(&machine, { kEye, kEye }));
+    EXPECT_EQ("RRRF", processSequenceBackward(&machine, asCodePoints(kEye, kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + U+1F441
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { kEye }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints(kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // Broken surrogates.
     // [Lead] + U+1F441
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { kLead, kEye }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints(kLead, kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + U+1F441
-    EXPECT_EQ("RRRF", processSequenceBackward(&machine, { 'a', kTrail, kEye }));
+    EXPECT_EQ("RRRF", processSequenceBackward(&machine, asCodePoints('a', kTrail, kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + U+1F441
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kEye }));
+        asCodePoints(kTrail, kTrail, kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + U+1F441
-    EXPECT_EQ("RRRF", processSequenceBackward(&machine, { kTrail, kEye }));
+    EXPECT_EQ("RRRF", processSequenceBackward(&machine, asCodePoints(kTrail, kEye)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest,
+TEST_F(BackwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyBefore_BMP_BMP)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + U+231A + U+FE0F
     EXPECT_EQ("RRF", processSequenceBackward(&machine,
-        { 'a', kWatch, kVS16 }));
+        asCodePoints('a', kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + U+231A + U+FE0F
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kEye, kWatch, kVS16 }));
+        asCodePoints(kEye, kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + U+231A + U+FE0F
-    EXPECT_EQ("RRF", processSequenceBackward(&machine, { kWatch, kVS16 }));
+    EXPECT_EQ("RRF", processSequenceBackward(&machine, asCodePoints(kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + U+231A + U+FE0F
     EXPECT_EQ("RRF", processSequenceBackward(&machine,
-        { kLead, kWatch, kVS16 }));
+        asCodePoints(kLead, kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + U+231A + U+FE0F
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kWatch, kVS16 }));
+        asCodePoints('a', kTrail, kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + U+231A + U+FE0F
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kWatch, kVS16 }));
+        asCodePoints(kTrail, kTrail, kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + U+231A + U+FE0F
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kTrail, kWatch, kVS16 }));
+        asCodePoints(kTrail, kWatch, kVS16)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest,
+TEST_F(BackwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyBefore_Supplementary_BMP)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + U+1F441 + U+FE0F
-    EXPECT_EQ("RRRF", processSequenceBackward(&machine, { 'a', kEye, kVS16 }));
+    EXPECT_EQ("RRRF", processSequenceBackward(&machine, asCodePoints('a', kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + U+1F441 + U+FE0F
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kEye, kEye, kVS16 }));
+        asCodePoints(kEye, kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + U+1F441 + U+FE0F
-    EXPECT_EQ("RRRF", processSequenceBackward(&machine, { kEye, kVS16 }));
+    EXPECT_EQ("RRRF", processSequenceBackward(&machine, asCodePoints(kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + U+1F441 + U+FE0F
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kLead, kEye, kVS16 }));
+        asCodePoints(kLead, kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + U+1F441 + U+FE0F
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kEye, kVS16 }));
+        asCodePoints('a', kTrail, kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + U+1F441 + U+FE0F
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kEye, kVS16 }));
+        asCodePoints(kTrail, kTrail, kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + U+1F441 + U+FE0F
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kTrail, kEye, kVS16 }));
+        asCodePoints(kTrail, kEye, kVS16)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest,
+TEST_F(BackwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyBefore_BMP_Supplementary)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + U+845B + U+E0100
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { 'a', kHanBMP, kVS17 }));
+        asCodePoints('a', kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + U+845B + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kEye, kHanBMP, kVS17 }));
+        asCodePoints(kEye, kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + U+845B + U+E0100
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kHanBMP, kVS17 }));
+        asCodePoints(kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + U+845B + U+E0100
     EXPECT_EQ("RRRF", processSequenceBackward(&machine,
-        { kLead, kHanBMP, kVS17 }));
+        asCodePoints(kLead, kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + U+845B + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kHanBMP, kVS17 }));
+        asCodePoints('a', kTrail, kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + U+845B + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kHanBMP, kVS17 }));
+        asCodePoints(kTrail, kTrail, kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + U+845B + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kTrail, kHanBMP, kVS17 }));
+        asCodePoints(kTrail, kHanBMP, kVS17)));
     EXPECT_EQ(-3, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest,
+TEST_F(BackwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyBefore_Supplementary_Supplementary)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + U+20000 + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { 'a', kHanSIP, kVS17 }));
+        asCodePoints('a', kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + U+20000 + U+E0100
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kEye, kHanSIP, kVS17 }));
+        asCodePoints(kEye, kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + U+20000 + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kHanSIP, kVS17 }));
+        asCodePoints(kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + U+20000 + U+E0100
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kLead, kHanSIP, kVS17 }));
+        asCodePoints(kLead, kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + U+20000 + U+E0100
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kHanSIP, kVS17 }));
+        asCodePoints('a', kTrail, kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + U+20000 + U+E0100
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kHanSIP, kVS17 }));
+        asCodePoints(kTrail, kTrail, kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + U+20000 + U+E0100
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kTrail, kHanSIP, kVS17 }));
+        asCodePoints(kTrail, kHanSIP, kVS17)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, MuchLongerCase)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, MuchLongerCase)
 {
     const UChar32 kMan = WTF::Unicode::manCharacter;
     const UChar32 kZwj = WTF::Unicode::zeroWidthJoinerCharacter;
@@ -316,157 +324,157 @@
     // emoji sequence.
     // 'a' + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRF", processSequenceBackward(&machine,
-        { 'a', kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints('a', kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRRF", processSequenceBackward(&machine,
-        { kEye, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints(kEye, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRF", processSequenceBackward(&machine,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRF", processSequenceBackward(&machine,
-        { kLead, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints(kLead, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints('a', kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints(kTrail, kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + ZWJ Emoji Sequence
     EXPECT_EQ("RRRRRRRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan}));
+        asCodePoints(kTrail, kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(-11, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, Flags_singleFlag)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, Flags_singleFlag)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + [U] + [S]
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { 'a', kRisU, kRisS }));
+        asCodePoints('a', kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + [U] + [S]
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kEye, kRisU, kRisS }));
+        asCodePoints(kEye, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [U] + [S]
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kRisU, kRisS }));
+        asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + [U] + [S]
     EXPECT_EQ("RRRRF", processSequenceBackward(&machine,
-        { kLead, kRisU, kRisS }));
+        asCodePoints(kLead, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + [U] + [S]
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kRisU, kRisS }));
+        asCodePoints('a', kTrail, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + [U] + [S]
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kRisU, kRisS }));
+        asCodePoints(kTrail, kTrail, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + [U] + [S]
     EXPECT_EQ("RRRRRF", processSequenceBackward(&machine,
-        { kTrail, kRisU, kRisS }));
+        asCodePoints(kTrail, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, Flags_twoFlags)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, Flags_twoFlags)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRF", processSequenceBackward(&machine,
-        { 'a', kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints('a', kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRRF", processSequenceBackward(&machine,
-        { kEye, kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints(kEye, kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRF", processSequenceBackward(&machine,
-        { kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints(kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRF", processSequenceBackward(&machine,
-        { kLead, kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints(kLead, kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints('a', kTrail, kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints(kTrail, kTrail, kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + [U] + [S] + [U] + [S]
     EXPECT_EQ("RRRRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kRisU, kRisS, kRisU, kRisS }));
+        asCodePoints(kTrail, kRisU, kRisS, kRisU, kRisS)));
     EXPECT_EQ(-4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(BackwardGraphemeBoundaryStatemachineTest, Flags_oddNumberedRIS)
+TEST_F(BackwardGraphemeBoundaryStatemachineTest, Flags_oddNumberedRIS)
 {
     BackwardGraphemeBoundaryStateMachine machine;
 
     // 'a' + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRF", processSequenceBackward(&machine,
-        { 'a', kRisU, kRisS, kRisU }));
+        asCodePoints('a', kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRRF", processSequenceBackward(&machine,
-        { kEye, kRisU, kRisS, kRisU }));
+        asCodePoints(kEye, kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRF", processSequenceBackward(&machine,
-        { kRisU, kRisS, kRisU }));
+        asCodePoints(kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRF", processSequenceBackward(&machine,
-        { kLead, kRisU, kRisS, kRisU }));
+        asCodePoints(kLead, kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRRF", processSequenceBackward(&machine,
-        { 'a', kTrail, kRisU, kRisS, kRisU }));
+        asCodePoints('a', kTrail, kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kTrail, kRisU, kRisS, kRisU }));
+        asCodePoints(kTrail, kTrail, kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + [U] + [S] + [U]
     EXPECT_EQ("RRRRRRRF", processSequenceBackward(&machine,
-        { kTrail, kRisU, kRisS, kRisU }));
+        asCodePoints(kTrail, kRisU, kRisS, kRisU)));
     EXPECT_EQ(-2, machine.finalizeAndGetBoundaryOffset());
 }
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachineTest.cpp b/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachineTest.cpp
index cdbb8c2d..6854acb1 100644
--- a/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachineTest.cpp
+++ b/third_party/WebKit/Source/core/editing/state_machines/ForwardGraphemeBoundaryStateMachineTest.cpp
@@ -40,8 +40,17 @@
 const UChar32 kRisS = 0x1F1F8;
 } // namespace
 
+class ForwardGraphemeBoundaryStatemachineTest : public GraphemeStateMachineTestBase {
+protected:
+    ForwardGraphemeBoundaryStatemachineTest() = default;
+    ~ForwardGraphemeBoundaryStatemachineTest() override = default;
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, DoNothingCase)
+private:
+    DISALLOW_COPY_AND_ASSIGN(ForwardGraphemeBoundaryStatemachineTest);
+};
+
+
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, DoNothingCase)
 {
     ForwardGraphemeBoundaryStateMachine machine;
 
@@ -49,383 +58,374 @@
     EXPECT_EQ(0, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, PrecedingText)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, PrecedingText)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
     // Preceding text should not affect the result except for flags.
     // SOT + | + 'a' + 'a'
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty, { 'a', 'a' }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRSRF", processSequenceForward(&machine,
-        { kRisU }, { 'a', 'a' }));
+        asCodePoints(kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRSRF", processSequenceForward(&machine,
-        { kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // U+0000 + | + 'a' + 'a'
-    EXPECT_EQ("SRF", processSequenceForward(&machine, { 0 }, { 'a', 'a' }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(0), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // U+0000 + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRSRF", processSequenceForward(&machine,
-        { 0, kRisU }, { 'a', 'a' }));
+        asCodePoints(0, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // U+0000 + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRSRF", processSequenceForward(&machine,
-        { 0, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(0, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + | + 'a' + 'a'
-    EXPECT_EQ("SRF", processSequenceForward(&machine, { 'a' }, { 'a', 'a' }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints('a'), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // 'a' + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRSRF", processSequenceForward(&machine,
-        { 'a', kRisU }, { 'a', 'a' }));
+        asCodePoints('a', kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // 'a' + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRSRF", processSequenceForward(&machine,
-        { 'a', kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints('a', kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + | + 'a' + 'a'
     EXPECT_EQ("RSRF", processSequenceForward(&machine,
-        { kEye }, { 'a', 'a' }));
+        asCodePoints(kEye), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // U+1F441 + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRRSRF", processSequenceForward(&machine,
-        { kEye, kRisU }, { 'a', 'a' }));
+        asCodePoints(kEye, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // U+1F441 + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRRSRF", processSequenceForward(&machine,
-        { kEye, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(kEye, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // Broken surrogates in preceding text.
 
     // [Lead] + | + 'a' + 'a'
     EXPECT_EQ("SRF", processSequenceForward(&machine,
-        { kLead }, { 'a', 'a' }));
+        asCodePoints(kLead), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // [Lead] + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRSRF", processSequenceForward(&machine,
-        { kLead, kRisU }, { 'a', 'a' }));
+        asCodePoints(kLead, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // [Lead] + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRSRF", processSequenceForward(&machine,
-        { kLead, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(kLead, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + | + 'a' + 'a'
     EXPECT_EQ("RSRF", processSequenceForward(&machine,
-        { 'a', kTrail }, { 'a', 'a' }));
+        asCodePoints('a', kTrail), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // 'a' + [Trail] + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRRSRF", processSequenceForward(&machine,
-        { 'a', kTrail, kRisU }, { 'a', 'a' }));
+        asCodePoints('a', kTrail, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // 'a' + [Trail] + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRRSRF", processSequenceForward(&machine,
-        { 'a', kTrail, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints('a', kTrail, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + | + 'a' + 'a'
     EXPECT_EQ("RSRF", processSequenceForward(&machine,
-        { kTrail, kTrail }, { 'a', 'a' }));
+        asCodePoints(kTrail, kTrail), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // [Trail] + [Trail] + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRRSRF", processSequenceForward(&machine,
-        { kTrail, kTrail, kRisU }, { 'a', 'a' }));
+        asCodePoints(kTrail, kTrail, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // [Trail] + [Trail] + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRRSRF", processSequenceForward(&machine,
-        { kTrail, kTrail, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(kTrail, kTrail, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + | + 'a' + 'a'
     EXPECT_EQ("RSRF", processSequenceForward(&machine,
-        { kTrail }, { 'a', 'a' }));
+        asCodePoints(kTrail), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + [Trail] + [U] + | + 'a' + 'a'
     EXPECT_EQ("RRRSRF", processSequenceForward(&machine,
-        { kTrail, kRisU }, { 'a', 'a' }));
+        asCodePoints(kTrail, kRisU), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + [Trail] + [U] + [S] + | + 'a' + 'a'
     EXPECT_EQ("RRRRRSRF", processSequenceForward(&machine,
-        { kTrail, kRisU, kRisS }, { 'a', 'a' }));
+        asCodePoints(kTrail, kRisU, kRisS), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, BrokenSurrogatePair)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, BrokenSurrogatePair)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
     // SOT + | + [Trail]
-    EXPECT_EQ("SF", processSequenceForward(&machine, kEmpty, { kTrail }));
+    EXPECT_EQ("SF", processSequenceForward(&machine, asCodePoints(), asCodePoints(kTrail)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + | + [Lead] + 'a'
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty, { kLead, 'a' }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(), asCodePoints(kLead, 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + | + [Lead] + [Lead]
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty,
-        { kLead, kLead }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kLead, kLead)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
     // SOT + | + [Lead] + EOT
-    EXPECT_EQ("SR", processSequenceForward(&machine, kEmpty, { kLead }));
+    EXPECT_EQ("SR", processSequenceForward(&machine, asCodePoints(), asCodePoints(kLead)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, BreakImmediately_BMP)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, BreakImmediately_BMP)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+0000 + U+0000
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty, { 0, 0 }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(), asCodePoints(0, 0)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + 'a'
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty, { 'a', 'a' }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(), asCodePoints('a', 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + U+1F441
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty, { 'a', kEye }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(), asCodePoints('a', kEye)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + EOT
-    EXPECT_EQ("SR", processSequenceForward(&machine, kEmpty, { 'a' }));
+    EXPECT_EQ("SR", processSequenceForward(&machine, asCodePoints(), asCodePoints('a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + [Trail]
-    EXPECT_EQ("SRF", processSequenceForward(&machine, kEmpty, { 'a', kTrail }));
+    EXPECT_EQ("SRF", processSequenceForward(&machine, asCodePoints(), asCodePoints('a', kTrail)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + [Lead] + 'a'
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty,
-        { 'a', kLead, 'a' }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints('a', kLead, 'a')));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + [Lead] + [Lead]
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty,
-        { 'a', kLead, kLead }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints('a', kLead, kLead)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + 'a' + [Lead] + EOT
-    EXPECT_EQ("SRR", processSequenceForward(&machine, kEmpty, { 'a', kLead }));
+    EXPECT_EQ("SRR", processSequenceForward(&machine, asCodePoints(), asCodePoints('a', kLead)));
     EXPECT_EQ(1, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, BreakImmediately_Supplementary)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, BreakImmediately_Supplementary)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+1F441 + 'a'
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty, { kEye, 'a' }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(), asCodePoints(kEye, 'a')));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+1F441
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kEye }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kEye)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + EOT
-    EXPECT_EQ("SRR", processSequenceForward(&machine, kEmpty, { kEye }));
+    EXPECT_EQ("SRR", processSequenceForward(&machine, asCodePoints(), asCodePoints(kEye)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + [Trail]
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kTrail }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kTrail)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + [Lead] + 'a'
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kLead, 'a' }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kLead, 'a')));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + [Lead] + [Lead]
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kLead, kLead }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kLead, kLead)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + [Lead] + EOT
-    EXPECT_EQ("SRRR", processSequenceForward(&machine, kEmpty,
-        { kEye, kLead }));
+    EXPECT_EQ("SRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kLead)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, NotBreakImmediatelyAfter_BMP_BMP)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, NotBreakImmediatelyAfter_BMP_BMP)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+231A + U+FE0F + 'a'
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, 'a' }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, 'a')));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + U+1F441
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, kEye }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, kEye)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + EOT
-    EXPECT_EQ("SRR", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16 }));
+    EXPECT_EQ("SRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + [Trail]
-    EXPECT_EQ("SRRF", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, kTrail }));
+    EXPECT_EQ("SRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, kTrail)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + [Lead] + 'a'
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, kLead, 'a' }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, kLead, 'a')));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + [Lead] + [Lead]
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, kLead, kLead }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, kLead, kLead)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+231A + U+FE0F + [Lead] + EOT
-    EXPECT_EQ("SRRR", processSequenceForward(&machine, kEmpty,
-        { kWatch, kVS16, kLead }));
+    EXPECT_EQ("SRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kWatch, kVS16, kLead)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest,
+TEST_F(ForwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyAfter_Supplementary_BMP)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+1F441 + U+FE0F + 'a'
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, 'a' }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, 'a')));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + U+1F441
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, kEye }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, kEye)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + EOT
-    EXPECT_EQ("SRRR", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16 }));
+    EXPECT_EQ("SRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + [Trail]
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, kTrail }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, kTrail)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + [Lead] + 'a'
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, kLead, 'a' }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, kLead, 'a')));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + [Lead] + [Lead]
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, kLead, kLead }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, kLead, kLead)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+1F441 + U+FE0F + [Lead] + EOT
-    EXPECT_EQ("SRRRR", processSequenceForward(&machine, kEmpty,
-        { kEye, kVS16, kLead }));
+    EXPECT_EQ("SRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kEye, kVS16, kLead)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest,
+TEST_F(ForwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyAfter_BMP_Supplementary)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+845B + U+E0100 + 'a'
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, 'a' }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, 'a')));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + U+1F441
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, kEye }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, kEye)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + EOT
-    EXPECT_EQ("SRRR", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17 }));
+    EXPECT_EQ("SRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + [Trail]
-    EXPECT_EQ("SRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, kTrail }));
+    EXPECT_EQ("SRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, kTrail)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + [Lead] + 'a'
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, kLead, 'a' }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, kLead, 'a')));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + [Lead] + [Lead]
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, kLead, kLead }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, kLead, kLead)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+845B + U+E0100 + [Lead] + EOT
-    EXPECT_EQ("SRRRR", processSequenceForward(&machine, kEmpty,
-        { kHanBMP, kVS17, kLead }));
+    EXPECT_EQ("SRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanBMP, kVS17, kLead)));
     EXPECT_EQ(3, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest,
+TEST_F(ForwardGraphemeBoundaryStatemachineTest,
     NotBreakImmediatelyAfter_Supplementary_Supplementary)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + U+20000 + U+E0100 + 'a'
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, 'a' }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, 'a')));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + U+1F441
-    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, kEye }));
+    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, kEye)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + EOT
-    EXPECT_EQ("SRRRR", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17 }));
+    EXPECT_EQ("SRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + [Trail]
-    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, kTrail }));
+    EXPECT_EQ("SRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, kTrail)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + [Lead] + 'a'
-    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, kLead, 'a' }));
+    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, kLead, 'a')));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + [Lead] + [Lead]
-    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, kLead, kLead }));
+    EXPECT_EQ("SRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, kLead, kLead)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + U+20000 + U+E0100 + [Lead] + EOT
-    EXPECT_EQ("SRRRRR", processSequenceForward(&machine, kEmpty,
-        { kHanSIP, kVS17, kLead }));
+    EXPECT_EQ("SRRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kHanSIP, kVS17, kLead)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, MuchLongerCase)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, MuchLongerCase)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     const UChar32 kMan = WTF::Unicode::manCharacter;
@@ -436,209 +436,208 @@
     // U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468 is a valid ZWJ
     // emoji sequence.
     // SOT + | + ZWJ Emoji Sequence + 'a'
-    EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+    EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + U+1F441
-    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kEye }));
+    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kEye)));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + EOT
-    EXPECT_EQ("SRRRRRRRRRRR", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan }));
+    EXPECT_EQ("SRRRRRRRRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan)));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + [Trail]
-    EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kTrail }));
+    EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kTrail)));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + [Lead] + 'a'
-    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead, 'a' }));
+    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + [Lead] + [Lead]
-    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead, kLead }));
+    EXPECT_EQ("SRRRRRRRRRRRRF", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead, kLead)));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + | + ZWJ Emoji Sequence + [Lead] + EOT
-    EXPECT_EQ("SRRRRRRRRRRRR", processSequenceForward(&machine, kEmpty,
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead }));
+    EXPECT_EQ("SRRRRRRRRRRRR", processSequenceForward(&machine, asCodePoints(),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, kLead)));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // Preceding text should not affect the result except for flags.
     // 'a' + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine,
-        { 'a' },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints('a'),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { kEye },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints(kEye),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("SRRRRRRRRRRRF", processSequenceForward(&machine,
-        { kLead },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints(kLead),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { 'a', kTrail },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints('a', kTrail),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { kTrail, kTrail },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints(kTrail, kTrail),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { kTrail },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints(kTrail),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [U] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RRSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { 'a', kRisU },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints('a', kRisU),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [U] + [S] + | + ZWJ Emoji Sequence + [Lead] + EOT
     EXPECT_EQ("RRRRSRRRRRRRRRRRF", processSequenceForward(&machine,
-        { 'a', kRisU, kRisS },
-        { kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a' }));
+        asCodePoints('a', kRisU, kRisS),
+        asCodePoints(kMan, kZwj, kHeart, kVS16, kZwj, kKiss, kZwj, kMan, 'a')));
     EXPECT_EQ(11, machine.finalizeAndGetBoundaryOffset());
 
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, singleFlags)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, singleFlags)
 {
-    const std::vector<UChar32> kEmpty;
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + | + [U] + [S]
     EXPECT_EQ("SRRRF", processSequenceForward(&machine,
-        kEmpty, { kRisU, kRisS }));
+        asCodePoints(), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + | + [U] + [S]
     EXPECT_EQ("SRRRF", processSequenceForward(&machine,
-        { 'a' }, { kRisU, kRisS }));
+        asCodePoints('a'), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + | + [U] + [S]
     EXPECT_EQ("RSRRRF", processSequenceForward(&machine,
-        { kEye }, { kRisU, kRisS }));
+        asCodePoints(kEye), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + | + [U] + [S]
     EXPECT_EQ("SRRRF", processSequenceForward(&machine,
-        { kLead }, { kRisU, kRisS }));
+        asCodePoints(kLead), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + | + [U] + [S]
     EXPECT_EQ("RSRRRF", processSequenceForward(&machine,
-        { 'a', kTrail }, { kRisU, kRisS }));
+        asCodePoints('a', kTrail), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + | + [U] + [S]
     EXPECT_EQ("RSRRRF", processSequenceForward(&machine,
-        { kTrail, kTrail }, { kRisU, kRisS }));
+        asCodePoints(kTrail, kTrail), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + | + [U] + [S]
     EXPECT_EQ("RSRRRF", processSequenceForward(&machine,
-        { kTrail }, { kRisU, kRisS }));
+        asCodePoints(kTrail), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, twoFlags)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, twoFlags)
 {
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRSRRRF", processSequenceForward(&machine,
-        { kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints(kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRSRRRF", processSequenceForward(&machine,
-        { 'a', kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints('a', kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRRSRRRF", processSequenceForward(&machine,
-        { kEye, kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints(kEye, kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRSRRRF", processSequenceForward(&machine,
-        { kLead, kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints(kLead, kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRRSRRRF", processSequenceForward(&machine,
-        { 'a', kTrail, kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints('a', kTrail, kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRRSRRRF", processSequenceForward(&machine,
-        { kTrail, kTrail, kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints(kTrail, kTrail, kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + [U] + [S] + | + [U] + [S]
     EXPECT_EQ("RRRRRSRRRF", processSequenceForward(&machine,
-        { kTrail, kRisU, kRisS }, { kRisU, kRisS }));
+        asCodePoints(kTrail, kRisU, kRisS), asCodePoints(kRisU, kRisS)));
     EXPECT_EQ(4, machine.finalizeAndGetBoundaryOffset());
 }
 
-TEST(ForwardGraphemeBoundaryStatemachineTest, oddNumberedFlags)
+TEST_F(ForwardGraphemeBoundaryStatemachineTest, oddNumberedFlags)
 {
     ForwardGraphemeBoundaryStateMachine machine;
 
     // SOT + [U] + | + [S] + [S]
     EXPECT_EQ("RRSRRRF", processSequenceForward(&machine,
-        { kRisU }, { kRisS, kRisU }));
+        asCodePoints(kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [U] + | + [S] + [S]
     EXPECT_EQ("RRSRRRF", processSequenceForward(&machine,
-        { 'a', kRisU }, { kRisS, kRisU }));
+        asCodePoints('a', kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // U+1F441 + [U] + | + [S] + [S]
     EXPECT_EQ("RRRSRRRF", processSequenceForward(&machine,
-        { kEye, kRisU }, { kRisS, kRisU }));
+        asCodePoints(kEye, kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // [Lead] + [U] + | + [S] + [S]
     EXPECT_EQ("RRSRRRF", processSequenceForward(&machine,
-        { kLead, kRisU }, { kRisS, kRisU }));
+        asCodePoints(kLead, kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // 'a' + [Trail] + [U] + | + [S] + [S]
     EXPECT_EQ("RRRSRRRF", processSequenceForward(&machine,
-        { 'a', kTrail, kRisU }, { kRisS, kRisU }));
+        asCodePoints('a', kTrail, kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // [Trail] + [Trail] + [U] + | + [S] + [S]
     EXPECT_EQ("RRRSRRRF", processSequenceForward(&machine,
-        { kTrail, kTrail, kRisU }, { kRisS, kRisU }));
+        asCodePoints(kTrail, kTrail, kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 
     // SOT + [Trail] + [U] + | + [S] + [S]
     EXPECT_EQ("RRRSRRRF", processSequenceForward(&machine,
-        { kTrail, kRisU }, { kRisS, kRisU }));
+        asCodePoints(kTrail, kRisU), asCodePoints(kRisS, kRisU)));
     EXPECT_EQ(2, machine.finalizeAndGetBoundaryOffset());
 }
 
diff --git a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp
index c009346..32851fd9 100644
--- a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp
+++ b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.cpp
@@ -8,8 +8,8 @@
 #include "core/editing/state_machines/ForwardGraphemeBoundaryStateMachine.h"
 #include "core/editing/state_machines/TextSegmentationMachineState.h"
 #include "wtf/Assertions.h"
+#include "wtf/text/StringBuilder.h"
 #include <algorithm>
-#include <vector>
 
 namespace blink {
 
@@ -28,87 +28,87 @@
     return *it;
 }
 
-std::vector<UChar> codePointsToCodeUnits(const std::vector<UChar32>& codePoints)
+Vector<UChar> codePointsToCodeUnits(const Vector<UChar32>& codePoints)
 {
-    std::vector<UChar> out;
+    Vector<UChar> out;
     for (const auto& codePoint : codePoints) {
         if (U16_LENGTH(codePoint) == 2) {
-            out.push_back(U16_LEAD(codePoint));
-            out.push_back(U16_TRAIL(codePoint));
+            out.append(U16_LEAD(codePoint));
+            out.append(U16_TRAIL(codePoint));
         } else {
-            out.push_back(static_cast<UChar>(codePoint));
+            out.append(static_cast<UChar>(codePoint));
         }
     }
     return out;
 }
 
 template<typename StateMachine>
-std::string processSequence(StateMachine* machine,
-    const std::vector<UChar32>& preceding,
-    const std::vector<UChar32>& following)
+String processSequence(StateMachine* machine,
+    const Vector<UChar32>& preceding,
+    const Vector<UChar32>& following)
 {
     machine->reset();
-    std::string out;
+    StringBuilder out;
     TextSegmentationMachineState state = TextSegmentationMachineState::Invalid;
-    std::vector<UChar> precedingCodeUnits = codePointsToCodeUnits(preceding);
+    Vector<UChar> precedingCodeUnits = codePointsToCodeUnits(preceding);
     std::reverse(precedingCodeUnits.begin(), precedingCodeUnits.end());
     for (const auto& codeUnit : precedingCodeUnits) {
         state = machine->feedPrecedingCodeUnit(codeUnit);
-        out += MachineStateToChar(state);
+        out.append(MachineStateToChar(state));
         switch (state) {
         case TextSegmentationMachineState::Invalid:
         case TextSegmentationMachineState::Finished:
-            return out;
+            return out.toString();
         case TextSegmentationMachineState::NeedMoreCodeUnit:
             continue;
         case TextSegmentationMachineState::NeedFollowingCodeUnit:
             break;
         }
     }
-    if (preceding.empty()
+    if (preceding.isEmpty()
         || state == TextSegmentationMachineState::NeedMoreCodeUnit) {
         state = machine->tellEndOfPrecedingText();
-        out += MachineStateToChar(state);
+        out.append(MachineStateToChar(state));
     }
     if (state == TextSegmentationMachineState::Finished)
-        return out;
+        return out.toString();
 
-    std::vector<UChar> followingCodeUnits = codePointsToCodeUnits(following);
+    Vector<UChar> followingCodeUnits = codePointsToCodeUnits(following);
     for (const auto& codeUnit : followingCodeUnits) {
         state = machine->feedFollowingCodeUnit(codeUnit);
-        out += MachineStateToChar(state);
+        out.append(MachineStateToChar(state));
         switch (state) {
         case TextSegmentationMachineState::Invalid:
         case TextSegmentationMachineState::Finished:
-            return out;
+            return out.toString();
         case TextSegmentationMachineState::NeedMoreCodeUnit:
             continue;
         case TextSegmentationMachineState::NeedFollowingCodeUnit:
             break;
         }
     }
-    return out;
+    return out.toString();
 }
 } // namespace
 
-std::string processSequenceBackward(
+String GraphemeStateMachineTestBase::processSequenceBackward(
     BackwardGraphemeBoundaryStateMachine* machine,
-    const std::vector<UChar32>& preceding)
+    const Vector<UChar32>& preceding)
 {
-    const std::string& out =
-        processSequence(machine, preceding, std::vector<UChar32>());
+    const String& out =
+        processSequence(machine, preceding, Vector<UChar32>());
     if (machine->finalizeAndGetBoundaryOffset()
         != machine->finalizeAndGetBoundaryOffset())
         return "State machine changes final offset after finished.";
     return out;
 }
 
-std::string processSequenceForward(
+String GraphemeStateMachineTestBase::processSequenceForward(
     ForwardGraphemeBoundaryStateMachine* machine,
-    const std::vector<UChar32>& preceding,
-    const std::vector<UChar32>& following)
+    const Vector<UChar32>& preceding,
+    const Vector<UChar32>& following)
 {
-    const std::string& out = processSequence(machine, preceding, following);
+    const String& out = processSequence(machine, preceding, following);
     if (machine->finalizeAndGetBoundaryOffset()
         != machine->finalizeAndGetBoundaryOffset())
         return "State machine changes final offset after finished.";
diff --git a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.h b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.h
index 8ad1d34..d4a6e83 100644
--- a/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.h
+++ b/third_party/WebKit/Source/core/editing/state_machines/StateMachineTestUtil.h
@@ -2,33 +2,56 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "wtf/Vector.h"
 #include "wtf/text/Unicode.h"
-
-#include <string>
-#include <vector>
+#include "wtf/text/WTFString.h"
 
 namespace blink {
 
 class BackwardGraphemeBoundaryStateMachine;
 class ForwardGraphemeBoundaryStateMachine;
 
-// Processes the |machine| with preceding/following code points.
-// The result string represents the output sequence of the state machine.
-// Each character represents returned state of each action.
-// I : Invalid
-// R : NeedMoreCodeUnit (Repeat)
-// S : NeedFollowingCodeUnit (Switch)
-// F : Finished
-//
-// For example, if a state machine returns following sequence:
-//   NeedMoreCodeUnit, NeedFollowingCodeUnit, Finished
-// the returned string will be "RSF".
-std::string processSequenceBackward(
-    BackwardGraphemeBoundaryStateMachine*,
-    const std::vector<UChar32>& preceding);
+class GraphemeStateMachineTestBase : public ::testing::Test {
+protected:
+    GraphemeStateMachineTestBase() = default;
+    ~GraphemeStateMachineTestBase() override = default;
 
-std::string processSequenceForward(
-    ForwardGraphemeBoundaryStateMachine*,
-    const std::vector<UChar32>& preceding,
-    const std::vector<UChar32>& following);
+    Vector<UChar32> asCodePoints() { return Vector<UChar32>(); }
+
+    template <typename ... Args>
+    Vector<UChar32> asCodePoints(Args... args)
+    {
+        UChar32 codePoints[] = {args...};
+        Vector<UChar32> result(sizeof...(args));
+        for (size_t index = 0; index < sizeof...(args); ++index)
+            result[index] = codePoints[index];
+        return result;
+    }
+
+    // Processes the |machine| with preceding/following code points.
+    // The result string represents the output sequence of the state machine.
+    // Each character represents returned state of each action.
+    // I : Invalid
+    // R : NeedMoreCodeUnit (Repeat)
+    // S : NeedFollowingCodeUnit (Switch)
+    // F : Finished
+    //
+    // For example, if a state machine returns following sequence:
+    //   NeedMoreCodeUnit, NeedFollowingCodeUnit, Finished
+    // the returned string will be "RSF".
+    String processSequenceBackward(
+        BackwardGraphemeBoundaryStateMachine*,
+        const Vector<UChar32>& preceding);
+
+    String processSequenceForward(
+        ForwardGraphemeBoundaryStateMachine*,
+        const Vector<UChar32>& preceding,
+        const Vector<UChar32>& following);
+
+private:
+    DISALLOW_COPY_AND_ASSIGN(GraphemeStateMachineTestBase);
+};
+
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index 5c2a8618..64ee2fc 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1112,6 +1112,8 @@
         FormValidationShowedMessage = 1294,
         WebAnimationsEasingAsFunctionLinear = 1295,
         WebAnimationsEasingAsFunctionOther = 1296,
+        // The above items are available in M51 branch
+
         V8Document_Images_AttributeGetter = 1297,
         V8Document_Embeds_AttributeGetter = 1298,
         V8Document_Plugins_AttributeGetter = 1299,
diff --git a/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp b/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
index e581a94..dc83244 100644
--- a/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
+++ b/third_party/WebKit/Source/core/html/AutoplayExperimentTest.cpp
@@ -116,7 +116,6 @@
         m_helper = AutoplayExperimentHelper::create(m_client.get());
     }
 
-#if ENABLE(OILPAN)
     void TearDown()
     {
         // Be sure that the mock is destructed before the test, so that any
@@ -127,7 +126,6 @@
         m_client.clear();
         Heap::collectAllGarbage();
     }
-#endif
 
     Persistent<MockAutoplayClient> m_client;
     Persistent<AutoplayExperimentHelper> m_helper;
diff --git a/third_party/WebKit/Source/core/html/ClassList.cpp b/third_party/WebKit/Source/core/html/ClassList.cpp
index c37b6bf..1637c65 100644
--- a/third_party/WebKit/Source/core/html/ClassList.cpp
+++ b/third_party/WebKit/Source/core/html/ClassList.cpp
@@ -32,20 +32,6 @@
 
 ClassList::ClassList(Element* element) : DOMTokenList(nullptr), m_element(element) { }
 
-#if !ENABLE(OILPAN)
-void ClassList::ref()
-{
-    m_element->ref();
-    DOMTokenList::ref();
-}
-
-void ClassList::deref()
-{
-    m_element->deref();
-    DOMTokenList::deref();
-}
-#endif
-
 unsigned ClassList::length() const
 {
     return m_element->hasClass() ? classNames().size() : 0;
diff --git a/third_party/WebKit/Source/core/html/ClassList.h b/third_party/WebKit/Source/core/html/ClassList.h
index 78734e4..1ee73c4 100644
--- a/third_party/WebKit/Source/core/html/ClassList.h
+++ b/third_party/WebKit/Source/core/html/ClassList.h
@@ -44,11 +44,6 @@
         return new ClassList(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/FormAssociatedElement.cpp b/third_party/WebKit/Source/core/html/FormAssociatedElement.cpp
index 3379b6fc..27fd630 100644
--- a/third_party/WebKit/Source/core/html/FormAssociatedElement.cpp
+++ b/third_party/WebKit/Source/core/html/FormAssociatedElement.cpp
@@ -153,11 +153,7 @@
     if (m_form)
         m_form->disassociate(*this);
     if (newForm) {
-#if ENABLE(OILPAN)
         m_form = newForm;
-#else
-        m_form = newForm->createWeakPtr();
-#endif
         m_form->associate(*this);
     } else {
         m_form = nullptr;
diff --git a/third_party/WebKit/Source/core/html/FormAssociatedElement.h b/third_party/WebKit/Source/core/html/FormAssociatedElement.h
index ffb5586f..1c93ee97 100644
--- a/third_party/WebKit/Source/core/html/FormAssociatedElement.h
+++ b/third_party/WebKit/Source/core/html/FormAssociatedElement.h
@@ -44,11 +44,6 @@
 public:
     virtual ~FormAssociatedElement();
 
-#if !ENABLE(OILPAN)
-    void ref() { refFormAssociatedElement(); }
-    void deref() { derefFormAssociatedElement(); }
-#endif
-
     static HTMLFormElement* findAssociatedForm(const HTMLElement*);
     HTMLFormElement* form() const { return m_form.get(); }
     ValidityState* validity();
@@ -118,11 +113,6 @@
     String customValidationMessage() const;
 
 private:
-#if !ENABLE(OILPAN)
-    virtual void refFormAssociatedElement() = 0;
-    virtual void derefFormAssociatedElement() = 0;
-#endif
-
     void setFormAttributeTargetObserver(FormAttributeTargetObserver*);
     void resetFormAttributeTargetObserver();
 
@@ -130,10 +120,7 @@
     Member<HTMLFormElement> m_form;
     Member<ValidityState> m_validityState;
     String m_customValidationMessage;
-    // Non-Oilpan: Even if m_formWasSetByParser is true, m_form can be null
-    // because parentNode is not a strong reference and |this| and m_form don't
-    // die together.
-    // Oilpan: If m_formWasSetByParser is true, m_form is always non-null.
+    // If m_formWasSetByParser is true, m_form is always non-null.
     bool m_formWasSetByParser;
 };
 
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
index f2a5096..f3c41f36 100644
--- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -151,10 +151,6 @@
 HTMLCanvasElement::~HTMLCanvasElement()
 {
     v8::Isolate::GetCurrent()->AdjustAmountOfExternalAllocatedMemory(-m_externallyAllocatedMemory);
-#if !ENABLE(OILPAN)
-    // Ensure these go away before the ImageBuffer.
-    m_context.clear();
-#endif
 }
 
 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value)
diff --git a/third_party/WebKit/Source/core/html/HTMLCollection.cpp b/third_party/WebKit/Source/core/html/HTMLCollection.cpp
index 36c91e5a..321070a 100644
--- a/third_party/WebKit/Source/core/html/HTMLCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLCollection.cpp
@@ -176,13 +176,6 @@
 
 HTMLCollection::~HTMLCollection()
 {
-#if !ENABLE(OILPAN)
-    if (hasValidIdNameCache())
-        unregisterIdNameCacheFromDocument(document());
-    // Named HTMLCollection types remove cache by themselves.
-    if (isUnnamedHTMLCollectionType(type()))
-        ownerNode().nodeLists()->removeCache(this, type());
-#endif
 }
 
 void HTMLCollection::invalidateCache(Document* oldDocument) const
diff --git a/third_party/WebKit/Source/core/html/HTMLDetailsElement.cpp b/third_party/WebKit/Source/core/html/HTMLDetailsElement.cpp
index 23e17542..bc329ff 100644
--- a/third_party/WebKit/Source/core/html/HTMLDetailsElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLDetailsElement.cpp
@@ -93,9 +93,6 @@
 
 HTMLDetailsElement::~HTMLDetailsElement()
 {
-#if !ENABLE(OILPAN)
-    detailsToggleEventSender().cancelEvent(this);
-#endif
 }
 
 void HTMLDetailsElement::dispatchPendingEvent(DetailsEventSender* eventSender)
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
index bf90461..164f664 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.cpp
@@ -65,15 +65,6 @@
 
 HTMLFormControlElement::~HTMLFormControlElement()
 {
-#if !ENABLE(OILPAN)
-#if ENABLE(ASSERT)
-    // Recalculate m_willValidate and m_isValid for the vtbl change in order to
-    // avoid assertion failures in isValidElement() called in setForm(0).
-    setNeedsWillValidateCheck();
-    setNeedsValidityCheck();
-#endif
-    setForm(0);
-#endif
 }
 
 DEFINE_TRACE(HTMLFormControlElement)
diff --git a/third_party/WebKit/Source/core/html/HTMLFormControlElement.h b/third_party/WebKit/Source/core/html/HTMLFormControlElement.h
index 3677256b..38d8d70 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormControlElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFormControlElement.h
@@ -120,11 +120,6 @@
     void setFocus(bool flag) override;
     void copyNonAttributePropertiesFromElement(const Element&) override;
 
-#if !ENABLE(OILPAN)
-    using Node::ref;
-    using Node::deref;
-#endif
-
 protected:
     HTMLFormControlElement(const QualifiedName& tagName, Document&, HTMLFormElement*);
 
@@ -156,11 +151,6 @@
     virtual bool supportsAutofocus() const;
 
 private:
-#if !ENABLE(OILPAN)
-    void refFormAssociatedElement() final { ref(); }
-    void derefFormAssociatedElement() final { deref(); }
-#endif
-
     bool isFormControlElement() const final { return true; }
     bool alwaysCreateUserAgentShadowRoot() const override { return true; }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
index c391040..c5200ed 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.cpp
@@ -64,9 +64,6 @@
 
 HTMLFormElement::HTMLFormElement(Document& document)
     : HTMLElement(formTag, document)
-#if !ENABLE(OILPAN)
-    , m_weakPtrFactory(this)
-#endif
     , m_associatedElementsAreDirty(false)
     , m_imageElementsAreDirty(false)
     , m_hasElementsAssociatedByParser(false)
@@ -88,12 +85,6 @@
 
 HTMLFormElement::~HTMLFormElement()
 {
-#if !ENABLE(OILPAN)
-    // With Oilpan, either removedFrom is called or the document and
-    // form controller are dead as well and there is no need to remove
-    // this form element from it.
-    document().formController().willDeleteForm(this);
-#endif
 }
 
 DEFINE_TRACE(HTMLFormElement)
@@ -189,9 +180,7 @@
             notifyFormRemovedFromTree(images, root);
         }
     }
-#if ENABLE(OILPAN)
     document().formController().willDeleteForm(this);
-#endif
     HTMLElement::removedFrom(insertionPoint);
 }
 
@@ -561,13 +550,6 @@
     removeFromPastNamesMap(e);
 }
 
-#if !ENABLE(OILPAN)
-WeakPtr<HTMLFormElement> HTMLFormElement::createWeakPtr()
-{
-    return m_weakPtrFactory.createWeakPtr();
-}
-#endif
-
 void HTMLFormElement::didAssociateByParser()
 {
     if (!m_didFinishParsingChildren)
diff --git a/third_party/WebKit/Source/core/html/HTMLFormElement.h b/third_party/WebKit/Source/core/html/HTMLFormElement.h
index c5361e4b..8f78550 100644
--- a/third_party/WebKit/Source/core/html/HTMLFormElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLFormElement.h
@@ -30,7 +30,6 @@
 #include "core/html/forms/RadioButtonGroupScope.h"
 #include "core/loader/FormSubmission.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/WeakPtr.h"
 
 namespace blink {
 
@@ -67,9 +66,6 @@
     void disassociate(FormAssociatedElement&);
     void associate(HTMLImageElement&);
     void disassociate(HTMLImageElement&);
-#if !ENABLE(OILPAN)
-    WeakPtr<HTMLFormElement> createWeakPtr();
-#endif
     void didAssociateByParser();
 
     void prepareForSubmission(Event*);
@@ -168,9 +164,7 @@
     FormAssociatedElement::List m_associatedElements;
     // Do not access m_imageElements directly. Use imageElements() instead.
     HeapVector<Member<HTMLImageElement>> m_imageElements;
-#if !ENABLE(OILPAN)
-    WeakPtrFactory<HTMLFormElement> m_weakPtrFactory;
-#endif
+
     bool m_associatedElementsAreDirty : 1;
     bool m_imageElementsAreDirty : 1;
     bool m_hasElementsAssociatedByParser : 1;
diff --git a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
index cbde096c..2304494 100644
--- a/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLFrameOwnerElement.cpp
@@ -80,10 +80,8 @@
                 currentParent->removeChild(child);
             if (newParent)
                 newParent->addChild(child);
-#if ENABLE(OILPAN)
             if (currentParent && !newParent)
                 child->dispose();
-#endif
         }
     }
 
@@ -122,9 +120,7 @@
             parent->addChild(child);
         } else if (toFrameView(child->parent())) {
             toFrameView(child->parent())->removeChild(child);
-#if ENABLE(OILPAN)
             child->dispose();
-#endif
         }
         return;
     }
diff --git a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
index 31bde6d..fb7c27d 100644
--- a/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLIFrameElement.cpp
@@ -54,9 +54,6 @@
 
 HTMLIFrameElement::~HTMLIFrameElement()
 {
-#if !ENABLE(OILPAN)
-    m_sandbox->setObserver(nullptr);
-#endif
 }
 
 DOMTokenList* HTMLIFrameElement::sandbox() const
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
index b6843b64..f389f1c 100644
--- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -72,9 +72,6 @@
             m_element->notifyViewportChanged();
     }
 
-#if !ENABLE(OILPAN)
-    void clearElement() { m_element = nullptr; }
-#endif
     DEFINE_INLINE_VIRTUAL_TRACE()
     {
         visitor->trace(m_element);
@@ -99,11 +96,7 @@
 {
     setHasCustomStyleCallbacks();
     if (form && form->inShadowIncludingDocument()) {
-#if ENABLE(OILPAN)
         m_form = form;
-#else
-        m_form = form->createWeakPtr();
-#endif
         m_formWasSetByParser = true;
         m_form->associate(*this);
         m_form->didAssociateByParser();
@@ -122,14 +115,6 @@
 
 HTMLImageElement::~HTMLImageElement()
 {
-#if !ENABLE(OILPAN)
-    if (m_listener) {
-        document().mediaQueryMatcher().removeViewportListener(m_listener.get());
-        m_listener->clearElement();
-    }
-    if (m_form)
-        m_form->disassociate(*this);
-#endif
 }
 
 DEFINE_TRACE(HTMLImageElement)
@@ -230,18 +215,10 @@
         m_form->disassociate(*this);
     }
     if (nearestForm) {
-#if ENABLE(OILPAN)
         m_form = nearestForm;
-#else
-        m_form = nearestForm->createWeakPtr();
-#endif
         m_form->associate(*this);
     } else {
-#if ENABLE(OILPAN)
         m_form = nullptr;
-#else
-        m_form = WeakPtr<HTMLFormElement>();
-#endif
     }
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLLabelElement.h b/third_party/WebKit/Source/core/html/HTMLLabelElement.h
index bab40b8a..533fd1e 100644
--- a/third_party/WebKit/Source/core/html/HTMLLabelElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLLabelElement.h
@@ -45,12 +45,6 @@
     HTMLFormElement* formOwner() const override;
     HTMLFormElement* formForBinding() const;
 
-
-#if !ENABLE(OILPAN)
-    using Node::ref;
-    using Node::deref;
-#endif
-
 private:
     explicit HTMLLabelElement(Document&, HTMLFormElement*);
     bool isInInteractiveContent(Node*) const;
@@ -74,10 +68,6 @@
     bool isFormControlElement() const override { return false; }
     bool isEnumeratable() const override { return false; }
     bool isLabelElement() const override { return true; }
-#if !ENABLE(OILPAN)
-    void refFormAssociatedElement() override { ref(); }
-    void derefFormAssociatedElement() override { deref(); }
-#endif
 
     void parseAttribute(const QualifiedName&, const AtomicString&, const AtomicString&) override;
 
diff --git a/third_party/WebKit/Source/core/html/HTMLMediaSource.h b/third_party/WebKit/Source/core/html/HTMLMediaSource.h
index 0af2921..796e6f4 100644
--- a/third_party/WebKit/Source/core/html/HTMLMediaSource.h
+++ b/third_party/WebKit/Source/core/html/HTMLMediaSource.h
@@ -47,11 +47,6 @@
     static void setRegistry(URLRegistry*);
     static HTMLMediaSource* lookup(const String& url) { return s_registry ? static_cast<HTMLMediaSource*>(s_registry->lookup(url)) : 0; }
 
-#if !ENABLE(OILPAN)
-    void ref() { refHTMLMediaSource(); }
-    void deref() { derefHTMLMediaSource(); }
-#endif
-
     // Called when an HTMLMediaElement is attempting to attach to this object,
     // and helps enforce attachment to at most one element at a time.
     // If already attached, returns false. Otherwise, must be in
@@ -66,10 +61,6 @@
     virtual double duration() const = 0;
     virtual TimeRanges* buffered() const = 0;
     virtual TimeRanges* seekable() const = 0;
-#if !ENABLE(OILPAN)
-    virtual void refHTMLMediaSource() = 0;
-    virtual void derefHTMLMediaSource() = 0;
-#endif
 
     // URLRegistrable
     URLRegistry& registry() const override { return *s_registry; }
diff --git a/third_party/WebKit/Source/core/html/HTMLNameCollection.cpp b/third_party/WebKit/Source/core/html/HTMLNameCollection.cpp
index 92f7e4d..1255441 100644
--- a/third_party/WebKit/Source/core/html/HTMLNameCollection.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLNameCollection.cpp
@@ -35,10 +35,6 @@
 HTMLNameCollection::~HTMLNameCollection()
 {
     ASSERT(type() == WindowNamedItems || type() == DocumentNamedItems);
-#if !ENABLE(OILPAN)
-    ASSERT(ownerNode().isDocumentNode());
-    ownerNode().nodeLists()->removeCache(this, type(), m_name);
-#endif
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
index 887114d..105f8d3 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.cpp
@@ -56,9 +56,6 @@
 
 inline HTMLObjectElement::~HTMLObjectElement()
 {
-#if !ENABLE(OILPAN)
-    setForm(0);
-#endif
 }
 
 HTMLObjectElement* HTMLObjectElement::create(Document& document, HTMLFormElement* form, bool createdByParser)
diff --git a/third_party/WebKit/Source/core/html/HTMLObjectElement.h b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
index 87db1b17..bcac853 100644
--- a/third_party/WebKit/Source/core/html/HTMLObjectElement.h
+++ b/third_party/WebKit/Source/core/html/HTMLObjectElement.h
@@ -61,11 +61,6 @@
     bool reportValidity() { return true; }
     void setCustomValidity(const String&) override { }
 
-#if !ENABLE(OILPAN)
-    using Node::ref;
-    using Node::deref;
-#endif
-
     bool canContainRangeEndPoint() const override { return useFallbackContent(); }
 
     bool isExposed() const;
@@ -104,11 +99,6 @@
 
     void reloadPluginOnAttributeChange(const QualifiedName&);
 
-#if !ENABLE(OILPAN)
-    void refFormAssociatedElement() override { ref(); }
-    void derefFormAssociatedElement() override { deref(); }
-#endif
-
     bool shouldRegisterAsNamedItem() const override { return true; }
     bool shouldRegisterAsExtraNamedItem() const override { return true; }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLOutputElement.cpp b/third_party/WebKit/Source/core/html/HTMLOutputElement.cpp
index b456ab6b..4b490905 100644
--- a/third_party/WebKit/Source/core/html/HTMLOutputElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLOutputElement.cpp
@@ -45,9 +45,6 @@
 
 HTMLOutputElement::~HTMLOutputElement()
 {
-#if !ENABLE(OILPAN)
-    m_tokens->setObserver(nullptr);
-#endif
 }
 
 HTMLOutputElement* HTMLOutputElement::create(Document& document, HTMLFormElement* form)
diff --git a/third_party/WebKit/Source/core/html/HTMLSourceElement.cpp b/third_party/WebKit/Source/core/html/HTMLSourceElement.cpp
index ac0e078..63d5c6b 100644
--- a/third_party/WebKit/Source/core/html/HTMLSourceElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLSourceElement.cpp
@@ -76,10 +76,6 @@
 
 HTMLSourceElement::~HTMLSourceElement()
 {
-#if !ENABLE(OILPAN)
-    sourceErrorEventSender().cancelEvent(this);
-    m_listener->clearElement();
-#endif
 }
 
 void HTMLSourceElement::createMediaQueryList(const AtomicString& media)
diff --git a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
index ff9639b..95873c0 100644
--- a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
@@ -51,11 +51,6 @@
 
 HTMLStyleElement::~HTMLStyleElement()
 {
-#if !ENABLE(OILPAN)
-    StyleElement::clearDocumentData(document(), this);
-
-    styleLoadEventSender().cancelEvent(this);
-#endif
 }
 
 HTMLStyleElement* HTMLStyleElement::create(Document& document, bool createdByParser)
diff --git a/third_party/WebKit/Source/core/html/HTMLTemplateElement.cpp b/third_party/WebKit/Source/core/html/HTMLTemplateElement.cpp
index 94ee864..f6dece6d 100644
--- a/third_party/WebKit/Source/core/html/HTMLTemplateElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTemplateElement.cpp
@@ -47,10 +47,6 @@
 
 HTMLTemplateElement::~HTMLTemplateElement()
 {
-#if !ENABLE(OILPAN)
-    if (m_content)
-        m_content->clearHost();
-#endif
 }
 
 DocumentFragment* HTMLTemplateElement::content() const
diff --git a/third_party/WebKit/Source/core/html/HTMLTrackElement.cpp b/third_party/WebKit/Source/core/html/HTMLTrackElement.cpp
index 95e37267..e51919a8 100644
--- a/third_party/WebKit/Source/core/html/HTMLTrackElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLTrackElement.cpp
@@ -60,10 +60,6 @@
 
 HTMLTrackElement::~HTMLTrackElement()
 {
-#if !ENABLE(OILPAN)
-    if (m_track)
-        m_track->clearTrackElement();
-#endif
 }
 
 Node::InsertionNotificationRequest HTMLTrackElement::insertedInto(ContainerNode* insertionPoint)
diff --git a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp
index 39575ef14..9bbd9d9 100644
--- a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.cpp
@@ -308,16 +308,6 @@
     }
 }
 
-#if !ENABLE(OILPAN)
-void HTMLViewSourceDocument::dispose()
-{
-    m_current.clear();
-    m_tbody.clear();
-    m_td.clear();
-    HTMLDocument::dispose();
-}
-#endif
-
 DEFINE_TRACE(HTMLViewSourceDocument)
 {
     visitor->trace(m_current);
diff --git a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h
index a4bed65..3bea2b25 100644
--- a/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h
+++ b/third_party/WebKit/Source/core/html/HTMLViewSourceDocument.h
@@ -47,10 +47,6 @@
 
     void addSource(const String&, HTMLToken&, SourceAnnotation);
 
-#if !ENABLE(OILPAN)
-    void dispose() override;
-#endif
-
     DECLARE_VIRTUAL_TRACE();
 
 private:
diff --git a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
index c05dcf1..376d0ad 100644
--- a/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/BaseChooserOnlyDateAndTimeInputType.cpp
@@ -40,16 +40,11 @@
 BaseChooserOnlyDateAndTimeInputType::BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element)
     : BaseDateAndTimeInputType(element)
 {
-#if ENABLE(OILPAN)
     ThreadState::current()->registerPreFinalizer(this);
-#endif
 }
 
 BaseChooserOnlyDateAndTimeInputType::~BaseChooserOnlyDateAndTimeInputType()
 {
-#if !ENABLE(OILPAN)
-    closeDateTimeChooser();
-#endif
     ASSERT(!m_dateTimeChooser);
 }
 
diff --git a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
index 2757aa60..3d764a5 100644
--- a/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/BaseMultipleFieldsDateAndTimeInputType.cpp
@@ -299,16 +299,6 @@
 
 BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
 {
-#if !ENABLE(OILPAN)
-    if (SpinButtonElement* element = spinButtonElement())
-        element->removeSpinButtonOwner();
-    if (ClearButtonElement* element = clearButtonElement())
-        element->removeClearButtonOwner();
-    if (DateTimeEditElement* element = dateTimeEditElement())
-        element->removeEditControlOwner();
-    if (PickerIndicatorElement* element = pickerIndicatorElement())
-        element->removePickerIndicatorOwner();
-#endif
 }
 
 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
diff --git a/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp b/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp
index 53621ab..4df443f9 100644
--- a/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp
+++ b/third_party/WebKit/Source/core/html/forms/RadioButtonGroupScope.cpp
@@ -50,11 +50,7 @@
     // The map records the 'required' state of each (button) element.
     using Members = HeapHashMap<Member<HTMLInputElement>, bool>;
 
-#if ENABLE(OILPAN)
     using MemberKeyValue = WTF::KeyValuePair<Member<HTMLInputElement>, bool>;
-#else
-    using MemberKeyValue = WTF::KeyValuePair<HTMLInputElement*, bool>;
-#endif
 
     void updateRequiredButton(MemberKeyValue&, bool isRequired);
 
diff --git a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
index 869d678..4419ad9 100644
--- a/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
+++ b/third_party/WebKit/Source/core/html/forms/TextFieldInputType.cpp
@@ -114,10 +114,6 @@
 
 TextFieldInputType::~TextFieldInputType()
 {
-#if !ENABLE(OILPAN)
-    if (SpinButtonElement* spinButton = spinButtonElement())
-        spinButton->removeSpinButtonOwner();
-#endif
 }
 
 SpinButtonElement* TextFieldInputType::spinButtonElement() const
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
index 5ab94103..28cc351 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.cpp
@@ -47,9 +47,6 @@
 HTMLImportChild::HTMLImportChild(const KURL& url, HTMLImportLoader* loader, SyncMode sync)
     : HTMLImport(sync)
     , m_url(url)
-#if !ENABLE(OILPAN)
-    , m_weakFactory(this)
-#endif
     , m_loader(loader)
     , m_client(nullptr)
 {
@@ -57,10 +54,6 @@
 
 HTMLImportChild::~HTMLImportChild()
 {
-#if !ENABLE(OILPAN)
-    // dispose() should be called before the destruction.
-    ASSERT(!m_loader);
-#endif
 }
 
 void HTMLImportChild::ownerInserted()
@@ -149,11 +142,7 @@
     ASSERT(!m_customElementMicrotaskStep);
 
     if (!hasFinishedLoading() && !formsCycle()) {
-#if ENABLE(OILPAN)
         m_customElementMicrotaskStep = CustomElement::didCreateImport(this);
-#else
-        m_customElementMicrotaskStep = CustomElement::didCreateImport(this)->weakPtr();
-#endif
     }
 }
 
@@ -178,15 +167,6 @@
     m_client = client;
 }
 
-#if !ENABLE(OILPAN)
-void HTMLImportChild::clearClient()
-{
-    // Doesn't check m_client nullity because we allow
-    // clearClient() to reenter.
-    m_client = nullptr;
-}
-#endif
-
 HTMLLinkElement* HTMLImportChild::link() const
 {
     if (!m_client)
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.h b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.h
index 35a52dd..d6471108 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportChild.h
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportChild.h
@@ -34,7 +34,6 @@
 #include "core/html/imports/HTMLImport.h"
 #include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
-#include "wtf/WeakPtr.h"
 
 namespace blink {
 
@@ -61,9 +60,6 @@
     void ownerInserted();
     void didShareLoader();
     void didStartLoading();
-#if !ENABLE(OILPAN)
-    WeakPtr<HTMLImportChild> weakPtr() { return m_weakFactory.createWeakPtr(); }
-#endif
 
     // HTMLImport
     Document* document() const override;
@@ -78,9 +74,6 @@
 #endif
 
     void setClient(HTMLImportChildClient*);
-#if !ENABLE(OILPAN)
-    void clearClient();
-#endif
 
     void didFinishLoading();
     void didFinishUpgradingCustomElements();
@@ -94,9 +87,6 @@
 
     KURL m_url;
     WeakMember<CustomElementMicrotaskImportStep> m_customElementMicrotaskStep;
-#if !ENABLE(OILPAN)
-    WeakPtrFactory<HTMLImportChild> m_weakFactory;
-#endif
     Member<HTMLImportLoader> m_loader;
     Member<HTMLImportChildClient> m_client;
 };
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
index 21bca5c..76009832 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.cpp
@@ -52,9 +52,6 @@
 
 HTMLImportLoader::~HTMLImportLoader()
 {
-#if !ENABLE(OILPAN)
-    dispose();
-#endif
 }
 
 void HTMLImportLoader::dispose()
@@ -69,7 +66,7 @@
     clearResource();
 }
 
-void HTMLImportLoader::startLoading(const RawPtr<RawResource>& resource)
+void HTMLImportLoader::startLoading(RawResource* resource)
 {
     setResource(resource);
 }
@@ -88,7 +85,6 @@
 
 void HTMLImportLoader::dataReceived(Resource*, const char* data, size_t length)
 {
-    RawPtr<DocumentWriter> protectingWriter(m_writer.get());
     m_writer->addData(data, length);
 }
 
@@ -143,7 +139,7 @@
     m_state = state;
 
     if (m_state == StateParsed || m_state == StateError || m_state == StateWritten) {
-        if (RawPtr<DocumentWriter> writer = m_writer.release())
+        if (DocumentWriter* writer = m_writer.release())
             writer->end();
     }
 
@@ -215,7 +211,7 @@
     return firstImport()->state().shouldBlockScriptExecution();
 }
 
-RawPtr<CustomElementSyncMicrotaskQueue> HTMLImportLoader::microtaskQueue() const
+CustomElementSyncMicrotaskQueue* HTMLImportLoader::microtaskQueue() const
 {
     return m_microtaskQueue;
 }
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
index cdeee8ca..bf28b7c1 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportLoader.h
@@ -48,12 +48,9 @@
 class HTMLImportsController;
 
 
-//
 // Owning imported Document lifetime. It also implements ResourceClient through ResourceOwner
 // to feed fetched bytes to the DocumentWriter of the imported document.
 // HTMLImportLoader is owned by HTMLImportsController.
-//
-//
 class HTMLImportLoader final : public GarbageCollectedFinalized<HTMLImportLoader>, public ResourceOwner<RawResource>, public DocumentParserClient {
     USING_GARBAGE_COLLECTED_MIXIN(HTMLImportLoader);
 public:
@@ -65,7 +62,7 @@
         StateError
     };
 
-    static RawPtr<HTMLImportLoader> create(HTMLImportsController* controller)
+    static HTMLImportLoader* create(HTMLImportsController* controller)
     {
         return new HTMLImportLoader(controller);
     }
@@ -85,14 +82,14 @@
     bool hasError() const { return m_state == StateError; }
     bool shouldBlockScriptExecution() const;
 
-    void startLoading(const RawPtr<RawResource>&);
+    void startLoading(RawResource*);
 
     // Tells the loader that all of the import's stylesheets finished
     // loading.
     // Called by Document::didRemoveAllPendingStylesheet.
     void didRemoveAllPendingStylesheet();
 
-    RawPtr<CustomElementSyncMicrotaskQueue> microtaskQueue() const;
+    CustomElementSyncMicrotaskQueue* microtaskQueue() const;
 
     DECLARE_VIRTUAL_TRACE();
 
@@ -118,9 +115,6 @@
     void setState(State);
     void didFinishLoading();
     bool hasPendingResources() const;
-#if !ENABLE(OILPAN)
-    void clear();
-#endif
 
     Member<HTMLImportsController> m_controller;
     HeapVector<Member<HTMLImportChild>> m_imports;
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
index 7c25adc2..f1ee701 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.cpp
@@ -11,7 +11,7 @@
 
 namespace blink {
 
-RawPtr<HTMLImportTreeRoot> HTMLImportTreeRoot::create(Document* document)
+HTMLImportTreeRoot* HTMLImportTreeRoot::create(Document* document)
 {
     return new HTMLImportTreeRoot(document);
 }
@@ -26,9 +26,6 @@
 
 HTMLImportTreeRoot::~HTMLImportTreeRoot()
 {
-#if !ENABLE(OILPAN)
-    dispose();
-#endif
 }
 
 void HTMLImportTreeRoot::dispose()
@@ -67,18 +64,13 @@
 
 void HTMLImportTreeRoot::scheduleRecalcState()
 {
-#if ENABLE(OILPAN)
     ASSERT(m_document);
     if (m_recalcTimer.isActive() || !m_document->isActive())
         return;
-#else
-    if (m_recalcTimer.isActive() || !m_document)
-        return;
-#endif
     m_recalcTimer.startOneShot(0, BLINK_FROM_HERE);
 }
 
-HTMLImportChild* HTMLImportTreeRoot::add(RawPtr<HTMLImportChild> child)
+HTMLImportChild* HTMLImportTreeRoot::add(HTMLImportChild* child)
 {
     m_imports.append(child);
     return m_imports.last().get();
@@ -98,7 +90,6 @@
 void HTMLImportTreeRoot::recalcTimerFired(Timer<HTMLImportTreeRoot>*)
 {
     ASSERT(m_document);
-    RawPtr<Document> protectDocument(m_document.get());
     HTMLImport::recalcTreeState(this);
 }
 
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.h b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.h
index ba7feac..317bf5d 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.h
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportTreeRoot.h
@@ -16,7 +16,7 @@
 
 class HTMLImportTreeRoot : public HTMLImport {
 public:
-    static RawPtr<HTMLImportTreeRoot> create(Document*);
+    static HTMLImportTreeRoot* create(Document*);
 
     ~HTMLImportTreeRoot() override;
     void dispose();
@@ -29,7 +29,7 @@
 
     void scheduleRecalcState();
 
-    HTMLImportChild* add(RawPtr<HTMLImportChild>);
+    HTMLImportChild* add(HTMLImportChild*);
     HTMLImportChild* find(const KURL&) const;
 
     DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp b/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
index 727dbfd..0337f26 100644
--- a/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
+++ b/third_party/WebKit/Source/core/html/imports/HTMLImportsController.cpp
@@ -48,9 +48,9 @@
 
 void HTMLImportsController::provideTo(Document& master)
 {
-    RawPtr<HTMLImportsController> controller = new HTMLImportsController(master);
-    master.setImportsController(controller.get());
-    Supplement<Document>::provideTo(master, supplementName(), controller.release());
+    HTMLImportsController* controller = new HTMLImportsController(master);
+    master.setImportsController(controller);
+    Supplement<Document>::provideTo(master, supplementName(), controller);
 }
 
 void HTMLImportsController::removeFrom(Document& master)
@@ -70,10 +70,6 @@
 
 HTMLImportsController::~HTMLImportsController()
 {
-#if !ENABLE(OILPAN)
-    // Verify that dispose() has been called.
-    ASSERT(!m_root);
-#endif
 }
 
 void HTMLImportsController::dispose()
@@ -104,11 +100,11 @@
     if (mode == HTMLImport::Async)
         UseCounter::count(root()->document(), UseCounter::HTMLImportsAsyncAttribute);
 
-    RawPtr<HTMLImportChild> child = new HTMLImportChild(url, loader, mode);
+    HTMLImportChild* child = new HTMLImportChild(url, loader, mode);
     child->setClient(client);
-    parent->appendImport(child.get());
-    loader->addImport(child.get());
-    return root()->add(child.release());
+    parent->appendImport(child);
+    loader->addImport(child);
+    return root()->add(child);
 }
 
 HTMLImportChild* HTMLImportsController::load(HTMLImport* parent, HTMLImportChildClient* client, FetchRequest request)
@@ -125,7 +121,7 @@
     }
 
     request.setCrossOriginAccessControl(master()->getSecurityOrigin(), CrossOriginAttributeAnonymous);
-    RawPtr<RawResource> resource = RawResource::fetchImport(request, parent->document()->fetcher());
+    RawResource* resource = RawResource::fetchImport(request, parent->document()->fetcher());
     if (!resource)
         return nullptr;
 
diff --git a/third_party/WebKit/Source/core/html/imports/LinkImport.cpp b/third_party/WebKit/Source/core/html/imports/LinkImport.cpp
index e4d49b5..82609c79 100644
--- a/third_party/WebKit/Source/core/html/imports/LinkImport.cpp
+++ b/third_party/WebKit/Source/core/html/imports/LinkImport.cpp
@@ -39,7 +39,7 @@
 
 namespace blink {
 
-RawPtr<LinkImport> LinkImport::create(HTMLLinkElement* owner)
+LinkImport* LinkImport::create(HTMLLinkElement* owner)
 {
     return new LinkImport(owner);
 }
@@ -52,12 +52,6 @@
 
 LinkImport::~LinkImport()
 {
-#if !ENABLE(OILPAN)
-    if (m_child) {
-        m_child->clearClient();
-        m_child = nullptr;
-    }
-#endif
 }
 
 Document* LinkImport::importedDocument() const
diff --git a/third_party/WebKit/Source/core/html/imports/LinkImport.h b/third_party/WebKit/Source/core/html/imports/LinkImport.h
index e1298f8..d512bb6 100644
--- a/third_party/WebKit/Source/core/html/imports/LinkImport.h
+++ b/third_party/WebKit/Source/core/html/imports/LinkImport.h
@@ -49,7 +49,7 @@
     USING_GARBAGE_COLLECTED_MIXIN(LinkImport);
 public:
 
-    static RawPtr<LinkImport> create(HTMLLinkElement* owner);
+    static LinkImport* create(HTMLLinkElement* owner);
 
     explicit LinkImport(HTMLLinkElement* owner);
     ~LinkImport() override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
index 75730e6..c289e73 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.cpp
@@ -1604,10 +1604,21 @@
             end = m_rowPositions[endLine] - m_rowPositions[0] + paddingBefore();
 
         // These vectors store line positions including gaps, but we shouldn't consider them for the edges of the grid.
-        if (endLine > firstExplicitLine && endLine < lastExplicitLine)
+        if (endLine > firstExplicitLine && endLine < lastExplicitLine) {
             end -= guttersSize(direction, 2);
+            end -= isForColumns ? m_offsetBetweenColumns : m_offsetBetweenRows;
+        }
     }
 
+    LayoutUnit alignmentOffset = isForColumns ? m_columnPositions[0] - borderAndPaddingStart() : m_rowPositions[0] - borderAndPaddingBefore();
+    if (isForColumns && !styleRef().isLeftToRightDirection())
+        alignmentOffset = contentLogicalWidth() - (m_columnPositions[m_columnPositions.size() - 1] - borderAndPaddingStart());
+
+    if (!startIsAuto)
+        start += alignmentOffset;
+    if (!endIsAuto)
+        end += alignmentOffset;
+
     breadth = end - start;
     offset = start;
 
@@ -1617,12 +1628,14 @@
         if (endIsAuto) {
             offset = LayoutUnit();
         } else {
-            LayoutUnit alignmentOffset =  m_columnPositions[0] - borderAndPaddingStart();
+            alignmentOffset = m_columnPositions[0] - borderAndPaddingStart();
             LayoutUnit offsetFromLastLine = m_columnPositions[m_columnPositions.size() - 1] - m_columnPositions[endLine];
-            offset = paddingLeft() +  alignmentOffset + offsetFromLastLine;
+            offset = paddingLeft() + alignmentOffset + offsetFromLastLine;
 
-            if (endLine > firstExplicitLine && endLine < lastExplicitLine)
+            if (endLine > firstExplicitLine && endLine < lastExplicitLine) {
                 offset += guttersSize(direction, 2);
+                offset += isForColumns ? m_offsetBetweenColumns : m_offsetBetweenRows;
+            }
         }
     }
 
@@ -1696,6 +1709,7 @@
     for (unsigned i = 0; i < nextToLastLine; ++i)
         m_columnPositions[i + 1] = m_columnPositions[i] + offset.distributionOffset + sizingData.columnTracks[i].baseSize() + trackGap;
     m_columnPositions[lastLine] = m_columnPositions[nextToLastLine] + sizingData.columnTracks[nextToLastLine].baseSize();
+    m_offsetBetweenColumns = offset.distributionOffset;
 
     numberOfTracks = sizingData.rowTracks.size();
     numberOfLines = numberOfTracks + 1;
@@ -1708,6 +1722,7 @@
     for (unsigned i = 0; i < nextToLastLine; ++i)
         m_rowPositions[i + 1] = m_rowPositions[i] + offset.distributionOffset + sizingData.rowTracks[i].baseSize() + trackGap;
     m_rowPositions[lastLine] = m_rowPositions[nextToLastLine] + sizingData.rowTracks[nextToLastLine].baseSize();
+    m_offsetBetweenRows = offset.distributionOffset;
 }
 
 static LayoutUnit computeOverflowAlignmentOffset(OverflowAlignment overflow, LayoutUnit trackBreadth, LayoutUnit childBreadth)
@@ -1936,12 +1951,6 @@
     return GridAxisStart;
 }
 
-static inline LayoutUnit offsetBetweenTracks(ContentDistributionType distribution, const Vector<GridTrack>& trackSizes, const Vector<LayoutUnit>& trackPositions, LayoutUnit trackGap)
-{
-    // FIXME: Perhaps a good idea to cache the result of this operation, since the ContentDistribution offset between tracks is always the same,
-    return (distribution == ContentDistributionStretch || distribution == ContentDistributionDefault) ? LayoutUnit() : trackPositions[1] - trackPositions[0] - trackSizes[0].baseSize() - trackGap;
-}
-
 LayoutUnit LayoutGrid::columnAxisOffsetForChild(const LayoutBox& child, GridSizingData& sizingData) const
 {
     const GridSpan& rowsSpan = cachedGridSpan(child, ForRows);
@@ -1968,7 +1977,7 @@
         // lines are all start plus a content-alignment distribution offset.
         // We must subtract last line's offset because is not part of the track the items belongs to.
         if (childEndLine - childStartLine > 1 && childEndLine < m_rowPositions.size() - 1)
-            endOfRow -= offsetBetweenTracks(styleRef().resolvedAlignContentDistribution(normalValueBehavior()), sizingData.rowTracks, m_rowPositions, trackGap);
+            endOfRow -= m_offsetBetweenRows;
         OverflowAlignment overflow = child.styleRef().resolvedAlignment(styleRef(), ItemPositionStretch).overflow();
         LayoutUnit offsetFromStartPosition = computeOverflowAlignmentOffset(overflow, endOfRow - startOfRow, childBreadth);
         return startPosition + (axisPosition == GridAxisEnd ? offsetFromStartPosition : offsetFromStartPosition / 2);
@@ -2005,7 +2014,7 @@
         // lines are all start plus a content-alignment distribution offset.
         // We must subtract last line's offset because is not part of the track the items belongs to.
         if (childEndLine - childStartLine > 1 && childEndLine < m_columnPositions.size() - 1)
-            endOfColumn -= offsetBetweenTracks(styleRef().resolvedJustifyContentDistribution(normalValueBehavior()), sizingData.columnTracks, m_columnPositions, trackGap);
+            endOfColumn -= m_offsetBetweenColumns;
         LayoutUnit offsetFromStartPosition = computeOverflowAlignmentOffset(child.styleRef().justifySelfOverflowAlignment(), endOfColumn - startOfColumn, childBreadth);
         return startPosition + (axisPosition == GridAxisEnd ? offsetFromStartPosition : offsetFromStartPosition / 2);
     }
diff --git a/third_party/WebKit/Source/core/layout/LayoutGrid.h b/third_party/WebKit/Source/core/layout/LayoutGrid.h
index 5314ed9..67010a9a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutGrid.h
+++ b/third_party/WebKit/Source/core/layout/LayoutGrid.h
@@ -214,6 +214,8 @@
     bool m_gridIsDirty;
     Vector<LayoutUnit> m_rowPositions;
     Vector<LayoutUnit> m_columnPositions;
+    LayoutUnit m_offsetBetweenColumns;
+    LayoutUnit m_offsetBetweenRows;
     HashMap<const LayoutBox*, GridArea> m_gridItemArea;
     OrderIterator m_orderIterator;
     Vector<LayoutBox*> m_gridItemsOverflowingGridArea;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 101e945..f2faa0ae 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -89,7 +89,7 @@
 #include "platform/geometry/TransformState.h"
 #include "platform/graphics/GraphicsContext.h"
 #include "platform/graphics/paint/PaintController.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/StringBuilder.h"
 #include "wtf/text/WTFString.h"
 #include <algorithm>
diff --git a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp
index f2b16d3..4da8c45 100644
--- a/third_party/WebKit/Source/core/layout/line/InlineBox.cpp
+++ b/third_party/WebKit/Source/core/layout/line/InlineBox.cpp
@@ -27,7 +27,7 @@
 #include "core/paint/BlockPainter.h"
 #include "core/paint/PaintInfo.h"
 #include "platform/fonts/FontMetrics.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 #ifndef NDEBUG
 #include <stdio.h>
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index bffd1705..771be03 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -86,8 +86,8 @@
 #include "platform/transforms/TransformationMatrix.h"
 #include "platform/transforms/TranslateTransformOperation.h"
 #include "public/platform/Platform.h"
-#include "wtf/Partitions.h"
 #include "wtf/StdLibExtras.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/CString.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
index 2681732..bc45783 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.cpp
@@ -31,6 +31,7 @@
 #include "core/workers/DedicatedWorkerThread.h"
 
 #include "core/workers/DedicatedWorkerGlobalScope.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerObjectProxy.h"
 #include "core/workers/WorkerThreadStartupData.h"
 
@@ -43,6 +44,7 @@
 
 DedicatedWorkerThread::DedicatedWorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerObjectProxy& workerObjectProxy, double timeOrigin)
     : WorkerThread(workerLoaderProxy, workerObjectProxy)
+    , m_workerBackingThread(WorkerBackingThread::create("DedicatedWorker Thread"))
     , m_workerObjectProxy(workerObjectProxy)
     , m_timeOrigin(timeOrigin)
 {
@@ -57,13 +59,6 @@
     return DedicatedWorkerGlobalScope::create(this, startupData, m_timeOrigin);
 }
 
-WebThreadSupportingGC& DedicatedWorkerThread::backingThread()
-{
-    if (!m_thread)
-        m_thread = WebThreadSupportingGC::create("DedicatedWorker Thread");
-    return *m_thread.get();
-}
-
 void DedicatedWorkerThread::postInitialize()
 {
     // Notify the parent object of our current active state before the event
diff --git a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h
index 476d9e1..3d1f9edf 100644
--- a/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h
+++ b/third_party/WebKit/Source/core/workers/DedicatedWorkerThread.h
@@ -41,20 +41,21 @@
 class DedicatedWorkerThread final : public WorkerThread {
 public:
     static PassOwnPtr<DedicatedWorkerThread> create(PassRefPtr<WorkerLoaderProxy>, WorkerObjectProxy&, double timeOrigin);
-    WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; }
     ~DedicatedWorkerThread() override;
 
+    WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; }
+    WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; }
+
 protected:
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
     void postInitialize() override;
-    WebThreadSupportingGC& backingThread() override;
 
 private:
     DedicatedWorkerThread(PassRefPtr<WorkerLoaderProxy>, WorkerObjectProxy&, double timeOrigin);
 
+    OwnPtr<WorkerBackingThread> m_workerBackingThread;
     WorkerObjectProxy& m_workerObjectProxy;
     double m_timeOrigin;
-    OwnPtr<WebThreadSupportingGC> m_thread;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
index 69a0d2b..e4c062c 100644
--- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.cpp
@@ -31,6 +31,7 @@
 #include "core/workers/SharedWorkerThread.h"
 
 #include "core/workers/SharedWorkerGlobalScope.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerThreadStartupData.h"
 
 namespace blink {
@@ -42,6 +43,7 @@
 
 SharedWorkerThread::SharedWorkerThread(const String& name, PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
     : WorkerThread(workerLoaderProxy, workerReportingProxy)
+    , m_workerBackingThread(WorkerBackingThread::create("SharedWorker Thread"))
     , m_name(name.isolatedCopy())
 {
 }
@@ -55,11 +57,4 @@
     return SharedWorkerGlobalScope::create(m_name, this, startupData);
 }
 
-WebThreadSupportingGC& SharedWorkerThread::backingThread()
-{
-    if (!m_thread)
-        m_thread = WebThreadSupportingGC::create("SharedWorker Thread");
-    return *m_thread.get();
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/SharedWorkerThread.h b/third_party/WebKit/Source/core/workers/SharedWorkerThread.h
index 8e2f07d..0945805 100644
--- a/third_party/WebKit/Source/core/workers/SharedWorkerThread.h
+++ b/third_party/WebKit/Source/core/workers/SharedWorkerThread.h
@@ -43,15 +43,16 @@
     static PassOwnPtr<SharedWorkerThread> create(const String& name, PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&);
     ~SharedWorkerThread() override;
 
+    WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; }
+
 protected:
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
-    WebThreadSupportingGC& backingThread() override;
 
 private:
     SharedWorkerThread(const String& name, PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&);
 
+    OwnPtr<WorkerBackingThread> m_workerBackingThread;
     String m_name;
-    OwnPtr<WebThreadSupportingGC> m_thread;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
new file mode 100644
index 0000000..18fb34dd
--- /dev/null
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.cpp
@@ -0,0 +1,95 @@
+// 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/workers/WorkerBackingThread.h"
+
+#include "bindings/core/v8/V8Binding.h"
+#include "bindings/core/v8/V8GCController.h"
+#include "bindings/core/v8/V8IdleTaskRunner.h"
+#include "bindings/core/v8/V8Initializer.h"
+#include "bindings/core/v8/V8PerIsolateData.h"
+#include "platform/RuntimeEnabledFeatures.h"
+#include "platform/ThreadSafeFunctional.h"
+#include "platform/WebThreadSupportingGC.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebTraceLocation.h"
+
+namespace blink {
+
+WorkerBackingThread::WorkerBackingThread(const char* name, bool shouldCallGCOnShutdown)
+    : m_backingThread(WebThreadSupportingGC::create(name))
+    , m_isOwningThread(true)
+    , m_shouldCallGCOnShutdown(shouldCallGCOnShutdown)
+{
+}
+
+WorkerBackingThread::WorkerBackingThread(WebThread* thread, bool shouldCallGCOnShutdown)
+    : m_backingThread(WebThreadSupportingGC::createForThread(thread))
+    , m_isOwningThread(false)
+    , m_shouldCallGCOnShutdown(shouldCallGCOnShutdown)
+{
+}
+
+WorkerBackingThread::~WorkerBackingThread()
+{
+#if ENABLE(ASSERT)
+    MutexLocker locker(m_mutex);
+    ASSERT(m_workerScriptCount == 0);
+#endif
+}
+
+void WorkerBackingThread::attach()
+{
+    {
+        MutexLocker locker(m_mutex);
+        if (++m_workerScriptCount > 1)
+            return;
+    }
+    initialize();
+}
+
+void WorkerBackingThread::detach()
+{
+    {
+        MutexLocker locker(m_mutex);
+        if (--m_workerScriptCount > 0)
+            return;
+    }
+    shutdown();
+}
+
+void WorkerBackingThread::initialize()
+{
+    ASSERT(!m_isolate);
+    m_isolate = V8PerIsolateData::initialize();
+    V8Initializer::initializeWorker(m_isolate);
+    m_backingThread->initialize();
+
+    OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(m_isolate));
+    ThreadState::current()->addInterruptor(interruptor.release());
+    ThreadState::current()->registerTraceDOMWrappers(m_isolate, V8GCController::traceDOMWrappers);
+    if (RuntimeEnabledFeatures::v8IdleTasksEnabled())
+        V8PerIsolateData::enableIdleTasks(m_isolate, adoptPtr(new V8IdleTaskRunner(backingThread().platformThread().scheduler())));
+    if (m_isOwningThread)
+        Platform::current()->didStartWorkerThread();
+}
+
+void WorkerBackingThread::shutdown()
+{
+    if (m_isOwningThread)
+        Platform::current()->willStopWorkerThread();
+
+    V8PerIsolateData::willBeDestroyed(m_isolate);
+    // TODO(yhirano): Remove this when https://crbug.com/v8/1428 is fixed.
+    if (m_shouldCallGCOnShutdown) {
+        // This statement runs only in tests.
+        V8GCController::collectAllGarbageForTesting(m_isolate);
+    }
+    m_backingThread->shutdown();
+
+    V8PerIsolateData::destroy(m_isolate);
+    m_isolate = nullptr;
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/workers/WorkerBackingThread.h b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
new file mode 100644
index 0000000..888f0fbdf
--- /dev/null
+++ b/third_party/WebKit/Source/core/workers/WorkerBackingThread.h
@@ -0,0 +1,81 @@
+// 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 WorkerBackingThread_h
+#define WorkerBackingThread_h
+
+#include "core/CoreExport.h"
+#include "wtf/Forward.h"
+#include "wtf/OwnPtr.h"
+#include "wtf/PassOwnPtr.h"
+#include "wtf/ThreadingPrimitives.h"
+#include <v8.h>
+
+namespace blink {
+
+class WebThread;
+class WebThreadSupportingGC;
+
+// WorkerBackingThread represents a WebThread with Oilpan and V8 potentially
+// shared by multiple WebWorker scripts. A WebWorker needs to call attach() when
+// attaching itself to the backing thread, and call detach() when the script
+// no longer needs the thread.
+// A WorkerBackingThread represents a WebThread while a WorkerThread corresponds
+// to a web worker. There is one-to-one correspondence between WorkerThread and
+// WorkerGlobalScope, but multiple WorkerThreads (i.e., multiple
+// WorkerGlobalScopes) can share one WorkerBackingThread.
+class CORE_EXPORT WorkerBackingThread final {
+public:
+    static PassOwnPtr<WorkerBackingThread> create(const char* name) { return adoptPtr(new WorkerBackingThread(name, false)); }
+    static PassOwnPtr<WorkerBackingThread> create(WebThread* thread) { return adoptPtr(new WorkerBackingThread(thread, false)); }
+
+    // These are needed to suppress leak reports. See
+    // https://crbug.com/590802 and https://crbug.com/v8/1428.
+    static PassOwnPtr<WorkerBackingThread> createForTest(const char* name) { return adoptPtr(new WorkerBackingThread(name, true)); }
+    static PassOwnPtr<WorkerBackingThread> createForTest(WebThread* thread) { return adoptPtr(new WorkerBackingThread(thread, true)); }
+
+    ~WorkerBackingThread();
+
+    // attach() and detach() attaches and detaches Oilpan and V8 to / from
+    // the caller worker script, respectively. attach() and detach() increments
+    // and decrements m_workerScriptCount. attach() initializes Oilpan and V8
+    // when m_workerScriptCount is 0. detach() terminates Oilpan and V8 when
+    // m_workerScriptCount is 1. A worker script must not call any function
+    // after calling detach().
+    // They should be called from |this| thread.
+    void attach();
+    void detach();
+
+    unsigned workerScriptCount()
+    {
+        MutexLocker locker(m_mutex);
+        return m_workerScriptCount;
+    }
+
+    WebThreadSupportingGC& backingThread()
+    {
+        ASSERT(m_backingThread);
+        return *m_backingThread;
+    }
+
+    v8::Isolate* isolate() { return m_isolate; }
+
+private:
+    WorkerBackingThread(const char* name, bool shouldCallGCOnShutdown);
+    WorkerBackingThread(WebThread*, bool shouldCallGCOnSHutdown);
+    void initialize();
+    void shutdown();
+
+    // Protects |m_workerScriptCount|.
+    Mutex m_mutex;
+    OwnPtr<WebThreadSupportingGC> m_backingThread;
+    v8::Isolate* m_isolate = nullptr;
+    unsigned m_workerScriptCount = 0;
+    bool m_isOwningThread;
+    bool m_shouldCallGCOnShutdown;
+};
+
+} // namespace blink
+
+#endif // WorkerBackingThread_h
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.cpp b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
index f9f67b0..f4e3d99 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.cpp
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.cpp
@@ -35,6 +35,7 @@
 #include "core/inspector/InspectorTaskRunner.h"
 #include "core/inspector/WorkerThreadDebugger.h"
 #include "core/workers/DedicatedWorkerGlobalScope.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerClients.h"
 #include "core/workers/WorkerReportingProxy.h"
 #include "core/workers/WorkerThreadStartupData.h"
@@ -43,7 +44,6 @@
 #include "platform/heap/SafePoint.h"
 #include "platform/heap/ThreadState.h"
 #include "platform/weborigin/KURL.h"
-#include "public/platform/Platform.h"
 #include "public/platform/WebScheduler.h"
 #include "public/platform/WebThread.h"
 #include "wtf/Functional.h"
@@ -125,8 +125,7 @@
     if (isInstrumented)
         isInstrumented = !task->taskNameForInstrumentation().isEmpty();
     if (isInstrumented) {
-        // TODO(hiroshige): This doesn't work when called on the main thread.
-        // https://crbug.com/588497
+        ASSERT(isCurrentThread());
         InspectorInstrumentation::asyncTaskScheduled(workerGlobalScope(), "Worker task", task.get());
     }
     return threadSafeBind(&WorkerThread::performTask, AllowCrossThreadAccess(this), task, isInstrumented);
@@ -143,7 +142,6 @@
     , m_workerLoaderProxy(workerLoaderProxy)
     , m_workerReportingProxy(workerReportingProxy)
     , m_webScheduler(nullptr)
-    , m_isolate(nullptr)
     , m_shutdownEvent(adoptPtr(new WaitableEvent(
         WaitableEvent::ResetPolicy::Manual,
         WaitableEvent::InitialState::NonSignaled)))
@@ -170,14 +168,14 @@
         return;
 
     m_started = true;
-    backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::initialize, AllowCrossThreadAccess(this), startupData));
+    workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::initialize, AllowCrossThreadAccess(this), startupData));
 }
 
 PlatformThreadId WorkerThread::platformThreadId()
 {
     if (!m_started)
         return 0;
-    return backingThread().platformThread().threadId();
+    return workerBackingThread().backingThread().platformThread().threadId();
 }
 
 void WorkerThread::initialize(PassOwnPtr<WorkerThreadStartupData> startupData)
@@ -187,7 +185,7 @@
     WorkerThreadStartMode startMode = startupData->m_startMode;
     OwnPtr<Vector<char>> cachedMetaData = startupData->m_cachedMetaData.release();
     V8CacheOptions v8CacheOptions = startupData->m_v8CacheOptions;
-    m_webScheduler = backingThread().platformThread().scheduler();
+    m_webScheduler = workerBackingThread().backingThread().platformThread().scheduler();
 
     {
         MutexLocker lock(m_threadStateMutex);
@@ -202,18 +200,18 @@
             return;
         }
 
-        m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this));
-        initializeBackingThread();
-        backingThread().addTaskObserver(m_microtaskRunner.get());
+        workerBackingThread().attach();
 
-        m_isolate = initializeIsolate();
+        if (shouldAttachThreadDebugger())
+            V8PerIsolateData::from(isolate())->setThreadDebugger(adoptPtr(new WorkerThreadDebugger(this, isolate())));
+        m_microtaskRunner = adoptPtr(new WorkerMicrotaskRunner(this));
+        workerBackingThread().backingThread().addTaskObserver(m_microtaskRunner.get());
+
         // Optimize for memory usage instead of latency for the worker isolate.
-        m_isolate->IsolateInBackgroundNotification();
+        isolate()->IsolateInBackgroundNotification();
         m_workerGlobalScope = createWorkerGlobalScope(startupData);
         m_workerGlobalScope->scriptLoaded(sourceCode.length(), cachedMetaData.get() ? cachedMetaData->size() : 0);
 
-        didStartWorkerThread();
-
         // Notify proxy that a new WorkerGlobalScope has been created and started.
         m_workerReportingProxy.workerGlobalScopeStarted(m_workerGlobalScope.get());
 
@@ -252,11 +250,7 @@
 
     workerGlobalScope()->dispose();
 
-    // This should be called after the WorkerGlobalScope's disposed (which may
-    // trigger some last-minutes cleanups) and before the thread actually stops.
-    willStopWorkerThread();
-
-    backingThread().removeTaskObserver(m_microtaskRunner.get());
+    workerBackingThread().backingThread().removeTaskObserver(m_microtaskRunner.get());
     postTask(BLINK_FROM_HERE, createSameThreadTask(&WorkerThread::performShutdownTask, this));
 }
 
@@ -268,10 +262,8 @@
     m_workerGlobalScope->notifyContextDestroyed();
     m_workerGlobalScope = nullptr;
 
-    willDestroyIsolate();
-    shutdownBackingThread();
-    destroyIsolate();
-    m_isolate = nullptr;
+    workerBackingThread().detach();
+    // We must not touch workerBackingThread() from now on.
 
     m_microtaskRunner = nullptr;
 
@@ -336,29 +328,34 @@
     // Ensure that tasks are being handled by thread event loop. If script execution weren't forbidden, a while(1) loop in JS could keep the thread alive forever.
     m_workerGlobalScope->scriptController()->willScheduleExecutionTermination();
 
-    // Terminating during debugger task may lead to crash due to heavy use of v8 api in debugger.
-    // Any debugger task is guaranteed to finish, so we can postpone termination after task has finished.
-    // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution access must be guarded by the lock.
-    if (m_runningDebuggerTask)
-        m_shouldTerminateV8Execution = true;
-    else
-        terminateV8Execution();
+    if (workerBackingThread().workerScriptCount() == 1) {
+        // This condition is not entirely correct because other scripts
+        // can be being initialized or terminated simuletaneously. Though this
+        // function itself is protected by a mutex, it is possible that
+        // |workerScriptCount()| here is not consistent with that in
+        // |initialize| and |shutdown|.
+        // TODO(yhirano): TerminateExecution should be called more carefully.
+        // https://crbug.com/413518
+        if (m_runningDebuggerTask) {
+            // Terminating during debugger task may lead to crash due to heavy
+            // use of v8 api in debugger. Any debugger task is guaranteed to
+            // finish, so we can postpone termination after task has finished.
+            // Note: m_runningDebuggerTask and m_shouldTerminateV8Execution
+            // access must be guarded by the lock.
+            m_shouldTerminateV8Execution = true;
+        } else {
+            isolate()->TerminateExecution();
+        }
+    }
 
     InspectorInstrumentation::allAsyncTasksCanceled(m_workerGlobalScope.get());
     m_inspectorTaskRunner->kill();
-    backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::shutdown, AllowCrossThreadAccess(this)));
+    workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::shutdown, AllowCrossThreadAccess(this)));
 }
 
-void WorkerThread::didStartWorkerThread()
+v8::Isolate* WorkerThread::isolate()
 {
-    ASSERT(isCurrentThread());
-    Platform::current()->didStartWorkerThread();
-}
-
-void WorkerThread::willStopWorkerThread()
-{
-    ASSERT(isCurrentThread());
-    Platform::current()->willStopWorkerThread();
+    return workerBackingThread().isolate();
 }
 
 void WorkerThread::terminateAndWaitForAllWorkers()
@@ -375,58 +372,12 @@
 
 bool WorkerThread::isCurrentThread()
 {
-    return m_started && backingThread().isCurrentThread();
+    return m_started && workerBackingThread().backingThread().isCurrentThread();
 }
 
 void WorkerThread::postTask(const WebTraceLocation& location, PassOwnPtr<ExecutionContextTask> task)
 {
-    backingThread().postTask(location, createWorkerThreadTask(task, true));
-}
-
-void WorkerThread::initializeBackingThread()
-{
-    ASSERT(isCurrentThread());
-    backingThread().initialize();
-}
-
-void WorkerThread::shutdownBackingThread()
-{
-    ASSERT(isCurrentThread());
-    backingThread().shutdown();
-}
-
-v8::Isolate* WorkerThread::initializeIsolate()
-{
-    ASSERT(isCurrentThread());
-    ASSERT(!m_isolate);
-    v8::Isolate* isolate = V8PerIsolateData::initialize();
-    V8Initializer::initializeWorker(isolate);
-
-    OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(isolate));
-    ThreadState::current()->addInterruptor(interruptor.release());
-    ThreadState::current()->registerTraceDOMWrappers(isolate, V8GCController::traceDOMWrappers);
-    if (RuntimeEnabledFeatures::v8IdleTasksEnabled())
-        V8PerIsolateData::enableIdleTasks(isolate, adoptPtr(new V8IdleTaskRunner(m_webScheduler)));
-    V8PerIsolateData::from(isolate)->setThreadDebugger(adoptPtr(new WorkerThreadDebugger(this, isolate)));
-    return isolate;
-}
-
-void WorkerThread::willDestroyIsolate()
-{
-    ASSERT(isCurrentThread());
-    ASSERT(m_isolate);
-    V8PerIsolateData::willBeDestroyed(m_isolate);
-}
-
-void WorkerThread::destroyIsolate()
-{
-    ASSERT(isCurrentThread());
-    V8PerIsolateData::destroy(m_isolate);
-}
-
-void WorkerThread::terminateV8Execution()
-{
-    m_isolate->TerminateExecution();
+    workerBackingThread().backingThread().postTask(location, createWorkerThreadTask(task, true));
 }
 
 void WorkerThread::runDebuggerTaskDontWait()
@@ -446,10 +397,10 @@
     m_inspectorTaskRunner->appendTask(threadSafeBind(&WorkerThread::runDebuggerTask, AllowCrossThreadAccess(this), task));
     {
         MutexLocker lock(m_threadStateMutex);
-        if (m_isolate)
-            m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(m_isolate);
+        if (isolate())
+            m_inspectorTaskRunner->interruptAndRunAllTasksDontWait(isolate());
     }
-    backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::runDebuggerTaskDontWait, AllowCrossThreadAccess(this)));
+    workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WorkerThread::runDebuggerTaskDontWait, AllowCrossThreadAccess(this)));
 }
 
 void WorkerThread::runDebuggerTask(PassOwnPtr<CrossThreadClosure> task)
@@ -468,7 +419,7 @@
         m_runningDebuggerTask = false;
         if (m_shouldTerminateV8Execution) {
             m_shouldTerminateV8Execution = false;
-            terminateV8Execution();
+            isolate()->TerminateExecution();
         }
     }
 }
diff --git a/third_party/WebKit/Source/core/workers/WorkerThread.h b/third_party/WebKit/Source/core/workers/WorkerThread.h
index 7b407ed..9bce956 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThread.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThread.h
@@ -44,6 +44,7 @@
 
 class InspectorTaskRunner;
 class WaitableEvent;
+class WorkerBackingThread;
 class WorkerGlobalScope;
 class WorkerInspectorController;
 class WorkerMicrotaskRunner;
@@ -64,16 +65,9 @@
     void start(PassOwnPtr<WorkerThreadStartupData>);
     void terminate();
 
-    // Returns the thread this worker runs on. Some implementations can create
-    // a new thread on the first call (e.g. shared, dedicated workers), whereas
-    // some implementations can use an existing thread that is already being
-    // used by other workers (e.g.  compositor workers).
-    virtual WebThreadSupportingGC& backingThread() = 0;
-
-    virtual void didStartWorkerThread();
-    virtual void willStopWorkerThread();
-
-    v8::Isolate* isolate() const { return m_isolate; }
+    virtual WorkerBackingThread& workerBackingThread() = 0;
+    virtual bool shouldAttachThreadDebugger() const { return true; }
+    v8::Isolate* isolate();
 
     // Can be used to wait for this worker thread to shut down.
     // (This is signaled on the main thread, so it's assumed to be waited on
@@ -122,17 +116,6 @@
 
     virtual void postInitialize() { }
 
-    // Both of these methods are called in the worker thread.
-    virtual void initializeBackingThread();
-    virtual void shutdownBackingThread();
-
-    virtual v8::Isolate* initializeIsolate();
-    virtual void willDestroyIsolate();
-    virtual void destroyIsolate();
-
-    // Can be called either on main or worker thread.
-    virtual void terminateV8Execution();
-
 private:
     friend class WorkerMicrotaskRunner;
 
@@ -162,13 +145,13 @@
     WorkerReportingProxy& m_workerReportingProxy;
     WebScheduler* m_webScheduler; // Not owned.
 
-    // This lock protects |m_workerGlobalScope|, |m_terminated|, |m_shutdown|, |m_isolate|, |m_runningDebuggerTask|, |m_shouldTerminateV8Execution| and |m_microtaskRunner|.
+    // This lock protects |m_workerGlobalScope|, |m_terminated|, |m_shutdown|,
+    // |m_runningDebuggerTask|, |m_shouldTerminateV8Execution| and
+    // |m_microtaskRunner|.
     Mutex m_threadStateMutex;
 
     Persistent<WorkerGlobalScope> m_workerGlobalScope;
 
-    v8::Isolate* m_isolate;
-
     // Used to signal thread shutdown.
     OwnPtr<WaitableEvent> m_shutdownEvent;
 
diff --git a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
index cec1466..43c0824 100644
--- a/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
+++ b/third_party/WebKit/Source/core/workers/WorkerThreadTestHelper.h
@@ -7,6 +7,7 @@
 #include "bindings/core/v8/V8GCController.h"
 #include "core/frame/csp/ContentSecurityPolicy.h"
 #include "core/inspector/ConsoleMessage.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerClients.h"
 #include "core/workers/WorkerLoaderProxy.h"
 #include "core/workers/WorkerReportingProxy.h"
@@ -69,25 +70,14 @@
         WorkerLoaderProxyProvider* mockWorkerLoaderProxyProvider,
         WorkerReportingProxy& mockWorkerReportingProxy)
         : WorkerThread(WorkerLoaderProxy::create(mockWorkerLoaderProxyProvider), mockWorkerReportingProxy)
-        , m_thread(WebThreadSupportingGC::create("Test thread"))
+        , m_workerBackingThread(WorkerBackingThread::createForTest("Test thread"))
         , m_scriptLoadedEvent(adoptPtr(new WaitableEvent()))
     {
-        ASSERT(m_thread);
     }
 
     ~WorkerThreadForTest() override { }
 
-    // WorkerThread implementation:
-    WebThreadSupportingGC& backingThread() override
-    {
-        ASSERT(m_thread);
-        return *m_thread;
-    }
-    void willDestroyIsolate() override
-    {
-        V8GCController::collectAllGarbageForTesting(v8::Isolate::GetCurrent());
-        WorkerThread::willDestroyIsolate();
-    }
+    WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; }
 
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
 
@@ -125,12 +115,12 @@
     void waitForInit()
     {
         OwnPtr<WaitableEvent> completionEvent = adoptPtr(new WaitableEvent());
-        backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WaitableEvent::signal, AllowCrossThreadAccess(completionEvent.get())));
+        workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&WaitableEvent::signal, AllowCrossThreadAccess(completionEvent.get())));
         completionEvent->wait();
     }
 
 private:
-    OwnPtr<WebThreadSupportingGC> m_thread;
+    OwnPtr<WorkerBackingThread> m_workerBackingThread;
     OwnPtr<WaitableEvent> m_scriptLoadedEvent;
 };
 
diff --git a/third_party/WebKit/Source/core/xml/XPathGrammar.y b/third_party/WebKit/Source/core/xml/XPathGrammar.y
index 6a0da53..bd3b1c1 100644
--- a/third_party/WebKit/Source/core/xml/XPathGrammar.y
+++ b/third_party/WebKit/Source/core/xml/XPathGrammar.y
@@ -34,7 +34,7 @@
 #include "core/xml/XPathPredicate.h"
 #include "core/xml/XPathStep.h"
 #include "core/xml/XPathVariableReference.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 void* yyFastMalloc(size_t size)
 {
diff --git a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp
index 735436c..22abd64 100644
--- a/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp
+++ b/third_party/WebKit/Source/core/xml/XSLTProcessorLibxslt.cpp
@@ -43,7 +43,7 @@
 #include "platform/network/ResourceResponse.h"
 #include "platform/weborigin/SecurityOrigin.h"
 #include "wtf/Assertions.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/CString.h"
 #include "wtf/text/StringBuffer.h"
 #include "wtf/text/UTF8.h"
diff --git a/third_party/WebKit/Source/modules/ModulesInitializer.cpp b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
index 4377ca9..c20f0b0 100644
--- a/third_party/WebKit/Source/modules/ModulesInitializer.cpp
+++ b/third_party/WebKit/Source/modules/ModulesInitializer.cpp
@@ -14,6 +14,7 @@
 #include "modules/IndexedDBNames.h"
 #include "modules/accessibility/AXObjectCacheImpl.h"
 #include "modules/canvas2d/CanvasRenderingContext2D.h"
+#include "modules/compositorworker/CompositorWorkerThread.h"
 #include "modules/filesystem/DraggedIsolatedFileSystemImpl.h"
 #include "modules/imagebitmap/ImageBitmapRenderingContext.h"
 #include "modules/offscreencanvas/OffscreenCanvas.h"
@@ -60,6 +61,7 @@
 {
     ASSERT(isInitialized());
     DatabaseManager::terminateDatabaseThread();
+    CompositorWorkerThread::clearSharedBackingThread();
     CoreInitializer::shutdown();
 }
 
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
index 004e2e6d..e68c9a31 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.cpp
@@ -6,6 +6,7 @@
 
 #include "bindings/core/v8/V8GCController.h"
 #include "bindings/core/v8/V8Initializer.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerObjectProxy.h"
 #include "core/workers/WorkerThreadStartupData.h"
 #include "modules/compositorworker/CompositorWorkerGlobalScope.h"
@@ -17,122 +18,26 @@
 
 namespace {
 
-void destroyThread(WebThreadSupportingGC* thread)
-{
-    ASSERT(isMainThread());
-    // The destructor for |thread| will block until all tasks have completed.
-    // This guarantees that shutdown will finish before the thread is destroyed.
-    delete thread;
-}
-
-class CompositorWorkerSharedState {
+class BackingThreadHolder {
 public:
-    static CompositorWorkerSharedState& instance()
+    static BackingThreadHolder& instance()
     {
-        DEFINE_THREAD_SAFE_STATIC_LOCAL(CompositorWorkerSharedState, compositorWorkerSharedState, (new CompositorWorkerSharedState()));
-        return compositorWorkerSharedState;
+        DEFINE_THREAD_SAFE_STATIC_LOCAL(BackingThreadHolder, holder, new BackingThreadHolder);
+        return holder;
     }
 
-    WebThreadSupportingGC* compositorWorkerThread()
+    WorkerBackingThread* thread() { return m_thread.get(); }
+    void clear() { m_thread = nullptr; }
+    void resetForTest()
     {
-        MutexLocker lock(m_mutex);
-        if (!m_thread && isMainThread()) {
-            ASSERT(!m_workerCount);
-            WebThread* platformThread = Platform::current()->compositorThread();
-            m_thread = WebThreadSupportingGC::createForThread(platformThread);
-        }
-        return m_thread.get();
-    }
-
-    void initializeBackingThread()
-    {
-        MutexLocker lock(m_mutex);
-        ASSERT(m_thread->isCurrentThread());
-        ++m_workerCount;
-        if (m_workerCount > 1)
-            return;
-
-        m_thread->initialize();
-
-        // Initialize the isolate at the same time.
-        ASSERT(!m_isolate);
-        m_isolate = V8PerIsolateData::initialize();
-        V8Initializer::initializeWorker(m_isolate);
-
-        OwnPtr<V8IsolateInterruptor> interruptor = adoptPtr(new V8IsolateInterruptor(m_isolate));
-        ThreadState::current()->addInterruptor(interruptor.release());
-        ThreadState::current()->registerTraceDOMWrappers(m_isolate, V8GCController::traceDOMWrappers);
-    }
-
-    void shutdownBackingThread()
-    {
-        MutexLocker lock(m_mutex);
-        ASSERT(m_thread->isCurrentThread());
-        ASSERT(m_workerCount > 0);
-        --m_workerCount;
-        if (m_workerCount == 0) {
-            m_thread->shutdown();
-            Platform::current()->mainThread()->getWebTaskRunner()->postTask(
-                BLINK_FROM_HERE, threadSafeBind(destroyThread, AllowCrossThreadAccess(m_thread.leakPtr())));
-        }
-    }
-
-    v8::Isolate* initializeIsolate()
-    {
-        MutexLocker lock(m_mutex);
-        ASSERT(m_thread->isCurrentThread());
-        ASSERT(m_isolate);
-        // It is safe to use the existing isolate even if TerminateExecution() has been
-        // called on it, without calling CancelTerminateExecution().
-        return m_isolate;
-    }
-
-    void willDestroyIsolate()
-    {
-        MutexLocker lock(m_mutex);
-        ASSERT(m_thread->isCurrentThread());
-        if (m_workerCount == 1)
-            V8PerIsolateData::willBeDestroyed(m_isolate);
-    }
-
-    void destroyIsolate()
-    {
-        MutexLocker lock(m_mutex);
-        if (!m_thread) {
-            ASSERT(m_workerCount == 0);
-            V8PerIsolateData::destroy(m_isolate);
-            m_isolate = nullptr;
-        }
-    }
-
-    void terminateV8Execution()
-    {
-        MutexLocker lock(m_mutex);
-        ASSERT(isMainThread() || m_thread->isCurrentThread());
-        if (m_workerCount > 1)
-            return;
-
-        m_isolate->TerminateExecution();
-    }
-
-    bool hasThreadForTest()
-    {
-        return m_thread;
-    }
-
-    bool hasIsolateForTest()
-    {
-        return m_isolate;
+        ASSERT(!m_thread || (m_thread->workerScriptCount() == 0));
+        m_thread = WorkerBackingThread::createForTest(Platform::current()->compositorThread());
     }
 
 private:
-    CompositorWorkerSharedState() {}
-    ~CompositorWorkerSharedState() {}
+    BackingThreadHolder() : m_thread(WorkerBackingThread::create(Platform::current()->compositorThread())) {}
 
-    Mutex m_mutex;
-    OwnPtr<WebThreadSupportingGC> m_thread;
-    int m_workerCount = 0;
-    v8::Isolate* m_isolate = nullptr;
+    OwnPtr<WorkerBackingThread> m_thread;
 };
 
 } // namespace
@@ -155,9 +60,9 @@
 {
 }
 
-WebThreadSupportingGC* CompositorWorkerThread::sharedBackingThread()
+WorkerBackingThread& CompositorWorkerThread::workerBackingThread()
 {
-    return CompositorWorkerSharedState::instance().compositorWorkerThread();
+    return *BackingThreadHolder::instance().thread();
 }
 
 WorkerGlobalScope*CompositorWorkerThread::createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData> startupData)
@@ -166,54 +71,14 @@
     return CompositorWorkerGlobalScope::create(this, startupData, m_timeOrigin);
 }
 
-WebThreadSupportingGC& CompositorWorkerThread::backingThread()
+void CompositorWorkerThread::clearSharedBackingThread()
 {
-    return *CompositorWorkerSharedState::instance().compositorWorkerThread();
+    BackingThreadHolder::instance().clear();
 }
 
-void CompositorWorkerThread::initializeBackingThread()
+void CompositorWorkerThread::resetSharedBackingThreadForTest()
 {
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::initializeBackingThread");
-    CompositorWorkerSharedState::instance().initializeBackingThread();
-}
-
-void CompositorWorkerThread::shutdownBackingThread()
-{
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::shutdownBackingThread");
-    CompositorWorkerSharedState::instance().shutdownBackingThread();
-}
-
-v8::Isolate* CompositorWorkerThread::initializeIsolate()
-{
-    return CompositorWorkerSharedState::instance().initializeIsolate();
-}
-
-void CompositorWorkerThread::willDestroyIsolate()
-{
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::willDestroyIsolate");
-    CompositorWorkerSharedState::instance().willDestroyIsolate();
-}
-
-void CompositorWorkerThread::destroyIsolate()
-{
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::destroyIsolate");
-    CompositorWorkerSharedState::instance().destroyIsolate();
-}
-
-void CompositorWorkerThread::terminateV8Execution()
-{
-    TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("compositor-worker"), "CompositorWorkerThread::terminateV8Execution");
-    CompositorWorkerSharedState::instance().terminateV8Execution();
-}
-
-bool CompositorWorkerThread::hasThreadForTest()
-{
-    return CompositorWorkerSharedState::instance().hasThreadForTest();
-}
-
-bool CompositorWorkerThread::hasIsolateForTest()
-{
-    return CompositorWorkerSharedState::instance().hasIsolateForTest();
+    BackingThreadHolder::instance().resetForTest();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
index 417b0b3..6c80a73 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThread.h
@@ -13,33 +13,22 @@
 class WorkerObjectProxy;
 
 // This class is overridden in unit-tests.
-class MODULES_EXPORT CompositorWorkerThread : public WorkerThread {
+class MODULES_EXPORT CompositorWorkerThread final : public WorkerThread {
 public:
     static PassOwnPtr<CompositorWorkerThread> create(PassRefPtr<WorkerLoaderProxy>, WorkerObjectProxy&, double timeOrigin);
     ~CompositorWorkerThread() override;
 
     WorkerObjectProxy& workerObjectProxy() const { return m_workerObjectProxy; }
+    WorkerBackingThread& workerBackingThread() override;
+    bool shouldAttachThreadDebugger() const override { return false; }
 
-    // Returns the shared backing thread for all CompositorWorkers.
-    static WebThreadSupportingGC* sharedBackingThread();
-
-    static bool hasThreadForTest();
-    static bool hasIsolateForTest();
+    static void resetSharedBackingThreadForTest();
+    static void clearSharedBackingThread();
 
 protected:
     CompositorWorkerThread(PassRefPtr<WorkerLoaderProxy>, WorkerObjectProxy&, double timeOrigin);
 
-    // WorkerThread:
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
-    WebThreadSupportingGC& backingThread() override;
-    void didStartWorkerThread() override { }
-    void willStopWorkerThread() override { }
-    void initializeBackingThread() override;
-    void shutdownBackingThread() override;
-    v8::Isolate* initializeIsolate() override;
-    void willDestroyIsolate() override;
-    void destroyIsolate() override;
-    void terminateV8Execution() override;
 
 private:
     WorkerObjectProxy& m_workerObjectProxy;
diff --git a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
index 32771ee..534df2f 100644
--- a/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
+++ b/third_party/WebKit/Source/modules/compositorworker/CompositorWorkerThreadTest.cpp
@@ -8,6 +8,7 @@
 #include "bindings/core/v8/V8GCController.h"
 #include "core/inspector/ConsoleMessage.h"
 #include "core/testing/DummyPageHolder.h"
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerLoaderProxy.h"
 #include "core/workers/WorkerObjectProxy.h"
 #include "core/workers/WorkerThreadStartupData.h"
@@ -23,48 +24,6 @@
 namespace blink {
 namespace {
 
-class TestCompositorWorkerThread : public CompositorWorkerThread {
-public:
-    TestCompositorWorkerThread(WorkerLoaderProxyProvider* loaderProxyProvider, WorkerObjectProxy& objectProxy, double timeOrigin, WaitableEvent* startEvent)
-        : CompositorWorkerThread(WorkerLoaderProxy::create(loaderProxyProvider), objectProxy, timeOrigin)
-        , m_startEvent(startEvent)
-    {
-    }
-
-    ~TestCompositorWorkerThread() override {}
-
-    void setCallbackAfterV8Termination(PassOwnPtr<Function<void()>> callback)
-    {
-        m_v8TerminationCallback = callback;
-    }
-
-private:
-    // WorkerThread:
-    void didStartWorkerThread() override
-    {
-        m_startEvent->signal();
-    }
-
-    void terminateV8Execution() override
-    {
-        // This could be called on worker thread, but not in the test.
-        ASSERT(isMainThread());
-        CompositorWorkerThread::terminateV8Execution();
-        if (m_v8TerminationCallback)
-            (*m_v8TerminationCallback)();
-    }
-
-    void willDestroyIsolate() override
-    {
-        v8::Isolate::GetCurrent()->RequestGarbageCollectionForTesting(v8::Isolate::kFullGarbageCollection);
-        Heap::collectAllGarbage();
-        CompositorWorkerThread::willDestroyIsolate();
-    }
-
-    WaitableEvent* m_startEvent;
-    OwnPtr<Function<void()>> m_v8TerminationCallback;
-};
-
 // A null WorkerObjectProxy, supplied when creating CompositorWorkerThreads.
 class TestCompositorWorkerObjectProxy : public WorkerObjectProxy {
 public:
@@ -122,6 +81,7 @@
 public:
     void SetUp() override
     {
+        CompositorWorkerThread::resetSharedBackingThreadForTest();
         m_page = DummyPageHolder::create();
         m_objectProxy = TestCompositorWorkerObjectProxy::create(&m_page->document());
         m_securityOrigin = SecurityOrigin::create(KURL(ParsedURLString, "http://fake.url/"));
@@ -129,14 +89,13 @@
 
     void TearDown() override
     {
-        ASSERT(!hasThread());
-        ASSERT(!hasIsolate());
         m_page.clear();
+        CompositorWorkerThread::resetSharedBackingThreadForTest();
     }
 
-    PassOwnPtr<TestCompositorWorkerThread> createCompositorWorker(WaitableEvent* startEvent)
+    PassOwnPtr<CompositorWorkerThread> createCompositorWorker()
     {
-        TestCompositorWorkerThread* workerThread = new TestCompositorWorkerThread(nullptr, *m_objectProxy, 0, startEvent);
+        OwnPtr<CompositorWorkerThread> workerThread = CompositorWorkerThread::create(nullptr, *m_objectProxy, 0);
         WorkerClients* clients = nullptr;
         workerThread->start(WorkerThreadStartupData::create(
             KURL(ParsedURLString, "http://fake.url/"),
@@ -149,42 +108,22 @@
             clients,
             WebAddressSpaceLocal,
             V8CacheOptionsDefault));
-        return adoptPtr(workerThread);
-    }
-
-    void createWorkerAdapter(OwnPtr<CompositorWorkerThread>* workerThread, WaitableEvent* creationEvent)
-    {
-        *workerThread = createCompositorWorker(creationEvent);
+        return workerThread.release();
     }
 
     // Attempts to run some simple script for |worker|.
     void checkWorkerCanExecuteScript(WorkerThread* worker)
     {
         OwnPtr<WaitableEvent> waitEvent = adoptPtr(new WaitableEvent());
-        worker->backingThread().platformThread().getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&CompositorWorkerThreadTest::executeScriptInWorker, AllowCrossThreadAccess(this),
+        worker->workerBackingThread().backingThread().postTask(BLINK_FROM_HERE, threadSafeBind(&CompositorWorkerThreadTest::executeScriptInWorker, AllowCrossThreadAccess(this),
             AllowCrossThreadAccess(worker), AllowCrossThreadAccess(waitEvent.get())));
         waitEvent->wait();
     }
 
-    void waitForWaitableEventAfterIteratingCurrentLoop(WaitableEvent* waitEvent)
-    {
-        testing::runPendingTasks();
-        waitEvent->wait();
-    }
-
-    bool hasThread() const
-    {
-        return CompositorWorkerThread::hasThreadForTest();
-    }
-
-    bool hasIsolate() const
-    {
-        return CompositorWorkerThread::hasIsolateForTest();
-    }
-
 private:
     void executeScriptInWorker(WorkerThread* worker, WaitableEvent* waitEvent)
     {
+        EXPECT_GT(worker->workerBackingThread().workerScriptCount(), 0u);
         WorkerOrWorkletScriptController* scriptController = worker->workerGlobalScope()->scriptController();
         bool evaluateResult = scriptController->evaluate(ScriptSourceCode("var counter = 0; ++counter;"));
         ASSERT_UNUSED(evaluateResult, evaluateResult);
@@ -199,9 +138,7 @@
 
 TEST_F(CompositorWorkerThreadTest, Basic)
 {
-    OwnPtr<WaitableEvent> creationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get());
-    waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
+    OwnPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker();
     checkWorkerCanExecuteScript(compositorWorker.get());
     compositorWorker->terminateAndWait();
 }
@@ -210,28 +147,23 @@
 TEST_F(CompositorWorkerThreadTest, CreateSecondAndTerminateFirst)
 {
     // Create the first worker and wait until it is initialized.
-    OwnPtr<WaitableEvent> firstCreationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<CompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get());
-    WebThreadSupportingGC* firstThread = CompositorWorkerThread::sharedBackingThread();
-    ASSERT(firstThread);
-    waitForWaitableEventAfterIteratingCurrentLoop(firstCreationEvent.get());
+    OwnPtr<CompositorWorkerThread> firstWorker = createCompositorWorker();
+    WebThreadSupportingGC* firstThread = &firstWorker->workerBackingThread().backingThread();
+    checkWorkerCanExecuteScript(firstWorker.get());
     v8::Isolate* firstIsolate = firstWorker->isolate();
-    ASSERT(firstIsolate);
+    ASSERT_TRUE(firstIsolate);
 
     // Create the second worker and immediately destroy the first worker.
-    OwnPtr<WaitableEvent> secondCreationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<CompositorWorkerThread> secondWorker = createCompositorWorker(secondCreationEvent.get());
+    OwnPtr<CompositorWorkerThread> secondWorker = createCompositorWorker();
     firstWorker->terminateAndWait();
 
     // Wait until the second worker is initialized. Verify that the second worker is using the same
     // thread and Isolate as the first worker.
-    WebThreadSupportingGC* secondThread = CompositorWorkerThread::sharedBackingThread();
-    ASSERT(secondThread);
-    waitForWaitableEventAfterIteratingCurrentLoop(secondCreationEvent.get());
-    EXPECT_EQ(firstThread, secondThread);
+    WebThreadSupportingGC* secondThread = &secondWorker->workerBackingThread().backingThread();
+    ASSERT_EQ(firstThread, secondThread);
 
     v8::Isolate* secondIsolate = secondWorker->isolate();
-    ASSERT(secondIsolate);
+    ASSERT_TRUE(secondIsolate);
     EXPECT_EQ(firstIsolate, secondIsolate);
 
     // Verify that the worker can still successfully execute script.
@@ -240,36 +172,26 @@
     secondWorker->terminateAndWait();
 }
 
-static void checkCurrentIsolate(v8::Isolate* isolate, WaitableEvent* event)
-{
-    EXPECT_EQ(v8::Isolate::GetCurrent(), isolate);
-    event->signal();
-}
-
 // Tests that a new WebThread is created if all existing workers are terminated before a new worker is created.
 TEST_F(CompositorWorkerThreadTest, TerminateFirstAndCreateSecond)
 {
     // Create the first worker, wait until it is initialized, and terminate it.
-    OwnPtr<WaitableEvent> creationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker(creationEvent.get());
-    WebThreadSupportingGC* firstThread = CompositorWorkerThread::sharedBackingThread();
-    waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
-    ASSERT(compositorWorker->isolate());
+    OwnPtr<CompositorWorkerThread> compositorWorker = createCompositorWorker();
+    WorkerBackingThread* workerBackingThread = &compositorWorker->workerBackingThread();
+    WebThreadSupportingGC* firstThread = &compositorWorker->workerBackingThread().backingThread();
+    checkWorkerCanExecuteScript(compositorWorker.get());
+
+    ASSERT_EQ(1u, workerBackingThread->workerScriptCount());
     compositorWorker->terminateAndWait();
 
-    // Create the second worker. Verify that the second worker lives in a different WebThread since the first
-    // thread will have been destroyed after destroying the first worker.
-    creationEvent = adoptPtr(new WaitableEvent());
-    compositorWorker = createCompositorWorker(creationEvent.get());
-    WebThreadSupportingGC* secondThread = CompositorWorkerThread::sharedBackingThread();
-    EXPECT_NE(firstThread, secondThread);
-    waitForWaitableEventAfterIteratingCurrentLoop(creationEvent.get());
+    ASSERT_EQ(0u, workerBackingThread->workerScriptCount());
 
-    // Jump over to the worker's thread to verify that the Isolate is set up correctly and execute script.
-    OwnPtr<WaitableEvent> checkEvent = adoptPtr(new WaitableEvent());
-    secondThread->platformThread().getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&checkCurrentIsolate, AllowCrossThreadAccess(compositorWorker->isolate()), AllowCrossThreadAccess(checkEvent.get())));
-    waitForWaitableEventAfterIteratingCurrentLoop(checkEvent.get());
+    // Create the second worker. The backing thread is same.
+    compositorWorker = createCompositorWorker();
+    WebThreadSupportingGC* secondThread = &compositorWorker->workerBackingThread().backingThread();
+    EXPECT_EQ(firstThread, secondThread);
     checkWorkerCanExecuteScript(compositorWorker.get());
+    ASSERT_EQ(1u, workerBackingThread->workerScriptCount());
 
     compositorWorker->terminateAndWait();
 }
@@ -277,23 +199,23 @@
 // Tests that v8::Isolate and WebThread are correctly set-up if a worker is created while another is terminating.
 TEST_F(CompositorWorkerThreadTest, CreatingSecondDuringTerminationOfFirst)
 {
-    OwnPtr<WaitableEvent> firstCreationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<TestCompositorWorkerThread> firstWorker = createCompositorWorker(firstCreationEvent.get());
-    waitForWaitableEventAfterIteratingCurrentLoop(firstCreationEvent.get());
+    OwnPtr<CompositorWorkerThread> firstWorker = createCompositorWorker();
+    checkWorkerCanExecuteScript(firstWorker.get());
     v8::Isolate* firstIsolate = firstWorker->isolate();
-    ASSERT(firstIsolate);
+    ASSERT_TRUE(firstIsolate);
 
-    // Request termination of the first worker, and set-up to make sure the second worker is created right as
-    // the first worker terminates its isolate.
-    OwnPtr<WaitableEvent> secondCreationEvent = adoptPtr(new WaitableEvent());
-    OwnPtr<CompositorWorkerThread> secondWorker;
-    firstWorker->setCallbackAfterV8Termination(bind(&CompositorWorkerThreadTest::createWorkerAdapter, this, &secondWorker, secondCreationEvent.get()));
-    firstWorker->terminateAndWait();
-    ASSERT(secondWorker);
+    // Request termination of the first worker and create the second worker
+    // as soon as possible.
+    EXPECT_EQ(1u, firstWorker->workerBackingThread().workerScriptCount());
+    firstWorker->terminate();
+    // We don't wait for its termination.
+    // Note: We rely on the assumption that the termination steps don't run
+    // on the worker thread so quickly. This could be a source of flakiness.
 
-    waitForWaitableEventAfterIteratingCurrentLoop(secondCreationEvent.get());
+    OwnPtr<CompositorWorkerThread> secondWorker = createCompositorWorker();
+
     v8::Isolate* secondIsolate = secondWorker->isolate();
-    ASSERT(secondIsolate);
+    ASSERT_TRUE(secondIsolate);
     EXPECT_EQ(firstIsolate, secondIsolate);
 
     // Verify that the isolate can run some scripts correctly in the second worker.
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
index e84a426..efa391c 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.cpp
@@ -30,6 +30,7 @@
 
 #include "modules/serviceworkers/ServiceWorkerThread.h"
 
+#include "core/workers/WorkerBackingThread.h"
 #include "core/workers/WorkerThreadStartupData.h"
 #include "modules/serviceworkers/ServiceWorkerGlobalScope.h"
 
@@ -42,6 +43,7 @@
 
 ServiceWorkerThread::ServiceWorkerThread(PassRefPtr<WorkerLoaderProxy> workerLoaderProxy, WorkerReportingProxy& workerReportingProxy)
     : WorkerThread(workerLoaderProxy, workerReportingProxy)
+    , m_workerBackingThread(WorkerBackingThread::create("ServiceWorker Thread"))
 {
 }
 
@@ -54,11 +56,4 @@
     return ServiceWorkerGlobalScope::create(this, startupData);
 }
 
-WebThreadSupportingGC& ServiceWorkerThread::backingThread()
-{
-    if (!m_thread)
-        m_thread = WebThreadSupportingGC::create("ServiceWorker Thread");
-    return *m_thread.get();
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h
index a39b429d..0a178d4a 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h
+++ b/third_party/WebKit/Source/modules/serviceworkers/ServiceWorkerThread.h
@@ -43,14 +43,14 @@
     static PassOwnPtr<ServiceWorkerThread> create(PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&);
     ~ServiceWorkerThread() override;
 
+    WorkerBackingThread& workerBackingThread() override { return *m_workerBackingThread; }
+
 protected:
     WorkerGlobalScope* createWorkerGlobalScope(PassOwnPtr<WorkerThreadStartupData>) override;
-    WebThreadSupportingGC& backingThread() override;
 
 private:
     ServiceWorkerThread(PassRefPtr<WorkerLoaderProxy>, WorkerReportingProxy&);
-
-    OwnPtr<WebThreadSupportingGC> m_thread;
+    OwnPtr<WorkerBackingThread> m_workerBackingThread;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
index 170d621..54de8b90b 100644
--- a/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
+++ b/third_party/WebKit/Source/platform/MemoryPurgeController.cpp
@@ -8,7 +8,7 @@
 #include "platform/TraceEvent.h"
 #include "platform/graphics/ImageDecodingStore.h"
 #include "public/platform/Platform.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/platform/PODArena.h b/third_party/WebKit/Source/platform/PODArena.h
index 7197a5e..90c5d289 100644
--- a/third_party/WebKit/Source/platform/PODArena.h
+++ b/third_party/WebKit/Source/platform/PODArena.h
@@ -30,10 +30,10 @@
 #include "wtf/Assertions.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/RefCounted.h"
 #include "wtf/Vector.h"
+#include "wtf/allocator/Partitions.h"
 #include <stdint.h>
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
index d269b29..3c7c362 100644
--- a/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
+++ b/third_party/WebKit/Source/platform/PartitionAllocMemoryDumpProvider.cpp
@@ -11,7 +11,7 @@
 #include "base/trace_event/trace_event_memory_overhead.h"
 #include "public/platform/WebMemoryAllocatorDump.h"
 #include "public/platform/WebProcessMemoryDump.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/WTFString.h"
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/audio/AudioArray.h b/third_party/WebKit/Source/platform/audio/AudioArray.h
index 32304f44..f63ac49 100644
--- a/third_party/WebKit/Source/platform/audio/AudioArray.h
+++ b/third_party/WebKit/Source/platform/audio/AudioArray.h
@@ -30,8 +30,8 @@
 #define AudioArray_h
 
 #include "wtf/Allocator.h"
-#include "wtf/Partitions.h"
 #include "wtf/Vector.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/build_config.h"
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index c7b0457..a8499f7 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -463,6 +463,8 @@
       'fonts/shaping/CachingWordShapeIterator.h',
       'fonts/shaping/CachingWordShaper.cpp',
       'fonts/shaping/CachingWordShaper.h',
+      'fonts/shaping/CaseMappingHarfBuzzBufferFiller.cpp',
+      'fonts/shaping/CaseMappingHarfBuzzBufferFiller.h',
       'fonts/shaping/HarfBuzzFace.cpp',
       'fonts/shaping/HarfBuzzFace.h',
       'fonts/shaping/HarfBuzzShaper.cpp',
diff --git a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
index 9709ab8..9ad92e8 100644
--- a/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/FontCustomPlatformData.cpp
@@ -58,7 +58,7 @@
         // FIXME: Skia currently renders synthetic bold and italics with
         // hinting and without linear metrics on the windows GDI backend
         // while the DirectWrite backend does the right thing. Using
-        // CreateFromName and specifying the bold/italics style allows
+        // legacyCreateTypeface and specifying the bold/italics style allows
         // for proper rendering of synthetic style. Once Skia has been
         // updated this workaround will no longer be needed.
         // http://crbug.com/332958
@@ -68,13 +68,12 @@
             SkString name;
             m_typeface->getFamilyName(&name);
 
-            int style = SkTypeface::kNormal;
-            if (syntheticBold)
-                style |= SkTypeface::kBold;
-            if (syntheticItalic)
-                style |= SkTypeface::kItalic;
-
-            RefPtr<SkTypeface> typeface = adoptRef(FontCache::fontCache()->fontManager()->legacyCreateTypeface(name.c_str(), static_cast<SkTypeface::Style>(style)));
+            SkFontStyle realStyle = m_typeface->fontStyle();
+            SkFontStyle syntheticStyle = SkFontStyle(
+                realStyle.weight() + (syntheticBold ? 200 : 0),
+                realStyle.width(),
+                syntheticItalic ? SkFontStyle::kItalic_Slant : realStyle.slant());
+            RefPtr<SkTypeface> typeface = adoptRef(FontCache::fontCache()->fontManager()->legacyCreateTypeface(name.c_str(), syntheticStyle));
             syntheticBold = false;
             syntheticItalic = false;
             return FontPlatformData(typeface.release(), "", size, syntheticBold, syntheticItalic, orientation);
diff --git a/third_party/WebKit/Source/platform/fonts/GlyphPage.h b/third_party/WebKit/Source/platform/fonts/GlyphPage.h
index 58d8b14..aeb177c5 100644
--- a/third_party/WebKit/Source/platform/fonts/GlyphPage.h
+++ b/third_party/WebKit/Source/platform/fonts/GlyphPage.h
@@ -34,10 +34,10 @@
 #include "platform/fonts/CustomFontData.h"
 #include "platform/fonts/Glyph.h"
 #include "wtf/Allocator.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RefCounted.h"
 #include "wtf/RefPtr.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/Unicode.h"
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
index f7d013ca..08cb662 100644
--- a/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
+++ b/third_party/WebKit/Source/platform/fonts/SimpleFontData.cpp
@@ -38,7 +38,7 @@
 #include "platform/fonts/VDMXParser.h"
 #include "platform/geometry/FloatRect.h"
 #include "wtf/MathExtras.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/CharacterNames.h"
 #include "wtf/text/Unicode.h"
 #include <unicode/unorm.h>
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.cpp b/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.cpp
new file mode 100644
index 0000000..e74e8209
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.cpp
@@ -0,0 +1,55 @@
+// 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 "CaseMappingHarfBuzzBufferFiller.h"
+
+#include "wtf/text/WTFString.h"
+
+namespace blink {
+
+static const uint16_t* toUint16(const UChar* src)
+{
+    // FIXME: This relies on undefined behavior however it works on the
+    // current versions of all compilers we care about and avoids making
+    // a copy of the string.
+    static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same size as uint16_t");
+    return reinterpret_cast<const uint16_t*>(src);
+}
+
+
+CaseMappingHarfBuzzBufferFiller::CaseMappingHarfBuzzBufferFiller(
+    CaseMapIntend caseMapIntend,
+    hb_buffer_t* harfBuzzBuffer,
+    const UChar* buffer,
+    unsigned bufferLength,
+    unsigned startIndex,
+    unsigned numCharacters)
+    : m_harfBuzzBuffer(harfBuzzBuffer)
+{
+
+    if (caseMapIntend == CaseMapIntend::KeepSameCase) {
+        hb_buffer_add_utf16(m_harfBuzzBuffer,
+            toUint16(buffer),
+            bufferLength,
+            startIndex,
+            numCharacters);
+    } else {
+        String caseMappedText;
+        if (caseMapIntend == CaseMapIntend::UpperCase) {
+            caseMappedText = String(buffer, bufferLength).upper();
+        } else {
+            caseMappedText = String(buffer, bufferLength).lower();
+        }
+        // TODO(drott): crbug.com/589335 Implement those for the case where the
+        // case-mapped string differs in length through one of the rule
+        // references in Unicode's SpecialCasing.txt
+
+        ASSERT(caseMappedText.length() == bufferLength);
+        ASSERT(!caseMappedText.is8Bit());
+        hb_buffer_add_utf16(m_harfBuzzBuffer, toUint16(caseMappedText.characters16()),
+            bufferLength, startIndex, numCharacters);
+    }
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h b/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h
new file mode 100644
index 0000000..a8a333038
--- /dev/null
+++ b/third_party/WebKit/Source/platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h
@@ -0,0 +1,39 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CaseMappingHarfBuzzBufferFiller_h
+#define CaseMappingHarfBuzzBufferFiller_h
+
+#include "wtf/Allocator.h"
+#include "wtf/text/Unicode.h"
+
+#include <hb.h>
+
+namespace blink {
+
+enum class CaseMapIntend {
+    KeepSameCase,
+    UpperCase,
+    LowerCase
+};
+
+class CaseMappingHarfBuzzBufferFiller {
+    STACK_ALLOCATED()
+
+public:
+    CaseMappingHarfBuzzBufferFiller(
+        CaseMapIntend,
+        hb_buffer_t* harfBuzzBuffer,
+        const UChar* buffer,
+        unsigned bufferLength,
+        unsigned startIndex,
+        unsigned numCharacters);
+
+private:
+    hb_buffer_t* m_harfBuzzBuffer;
+};
+
+} // namespace blink
+
+#endif
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
index 20433ca4..8fce6cb2 100644
--- a/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
+++ b/third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaper.cpp
@@ -36,6 +36,7 @@
 #include "platform/fonts/FontFallbackIterator.h"
 #include "platform/fonts/GlyphBuffer.h"
 #include "platform/fonts/UTF16TextIterator.h"
+#include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h"
 #include "platform/fonts/shaping/HarfBuzzFace.h"
 #include "platform/fonts/shaping/RunSegmenter.h"
 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
@@ -240,37 +241,6 @@
     return dir == RTL ? HB_DIRECTION_REVERSE(harfBuzzDirection) : harfBuzzDirection;
 }
 
-static const uint16_t* toUint16(const UChar* src)
-{
-    // FIXME: This relies on undefined behavior however it works on the
-    // current versions of all compilers we care about and avoids making
-    // a copy of the string.
-    static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same size as uint16_t");
-    return reinterpret_cast<const uint16_t*>(src);
-}
-
-static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer,
-    const FontDescription& fontDescription, const UChar* normalizedBuffer,
-    unsigned normalizedBufferLength, unsigned startIndex, unsigned numCharacters)
-{
-    // TODO: Revisit whether we can always fill the hb_buffer_t with the
-    // full run text, but only specify startIndex and numCharacters for the part
-    // to be shaped. Then simplify/change the complicated index computations in
-    // extractShapeResults().
-    if (fontDescription.variant() == FontVariantSmallCaps) {
-        String upperText = String(normalizedBuffer, normalizedBufferLength)
-            .upper();
-        // TextRun is 16 bit, therefore upperText is 16 bit, even after we call
-        // makeUpper().
-        ASSERT(!upperText.is8Bit());
-        hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()),
-            normalizedBufferLength, startIndex, numCharacters);
-    } else {
-        hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer),
-            normalizedBufferLength, startIndex, numCharacters);
-    }
-}
-
 inline bool HarfBuzzShaper::shapeRange(hb_buffer_t* harfBuzzBuffer,
     unsigned startIndex,
     unsigned numCharacters,
@@ -291,10 +261,6 @@
     hb_buffer_set_direction(harfBuzzBuffer, TextDirectionToHBDirection(m_textRun.direction(),
         m_font->getFontDescription().orientation(), currentFont));
 
-    addToHarfBuzzBufferInternal(harfBuzzBuffer,
-        m_font->getFontDescription(), m_normalizedBuffer.get(), m_normalizedBufferLength,
-        startIndex, numCharacters);
-
     HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(currentFontRangeSet), hb_font_destroy);
     hb_shape(harfBuzzFont.get(), harfBuzzBuffer, m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
 
@@ -558,6 +524,17 @@
                 m_font->getFontDescription().orientation(),
                 segmentRange.renderOrientation);
 
+            CaseMapIntend caseMapIntend =
+                m_font->getFontDescription().variant() == FontVariantSmallCaps
+                ? CaseMapIntend::UpperCase : CaseMapIntend::KeepSameCase;
+            CaseMappingHarfBuzzBufferFiller(
+                caseMapIntend,
+                harfBuzzBuffer.get(),
+                m_normalizedBuffer.get(),
+                m_normalizedBufferLength,
+                currentQueueItem.m_startIndex,
+                currentQueueItem.m_numCharacters);
+
             if (!shapeRange(harfBuzzBuffer.get(),
                 currentQueueItem.m_startIndex,
                 currentQueueItem.m_numCharacters,
diff --git a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
index 59cd332..dd414101 100644
--- a/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
+++ b/third_party/WebKit/Source/platform/fonts/skia/FontCacheSkia.cpp
@@ -210,12 +210,6 @@
         name = family.utf8();
     }
 
-    int style = SkTypeface::kNormal;
-    if (fontDescription.weight() >= FontWeight600)
-        style |= SkTypeface::kBold;
-    if (fontDescription.style())
-        style |= SkTypeface::kItalic;
-
 #if OS(WIN)
     if (s_sideloadedFonts) {
         HashMap<String, RefPtr<SkTypeface>>::iterator sideloadedFont =
@@ -227,7 +221,7 @@
     if (m_fontManager) {
         return adoptRef(useDirectWrite()
             ? m_fontManager->matchFamilyStyle(name.data(), fontStyle(fontDescription))
-            : m_fontManager->legacyCreateTypeface(name.data(), style)
+            : m_fontManager->legacyCreateTypeface(name.data(), fontStyle(fontDescription))
             );
     }
 #endif
@@ -242,6 +236,11 @@
 
     // FIXME: Use m_fontManager, SkFontStyle and matchFamilyStyle instead of
     // CreateFromName on all platforms.
+    int style = SkTypeface::kNormal;
+    if (fontDescription.weight() >= FontWeight600)
+        style |= SkTypeface::kBold;
+    if (fontDescription.style())
+        style |= SkTypeface::kItalic;
     return adoptRef(SkTypeface::CreateFromName(name.data(), static_cast<SkTypeface::Style>(style)));
 }
 
diff --git a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
index c2a17f5..83e6b44 100644
--- a/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
+++ b/third_party/WebKit/Source/platform/fonts/win/FontFallbackWin.cpp
@@ -52,7 +52,7 @@
     if (FontCache::useDirectWrite())
         typeface = fontManager->matchFamilyStyle(family.utf8().data(), SkFontStyle());
     else
-        typeface = fontManager->legacyCreateTypeface(family.utf8().data(), SkTypeface::kNormal);
+        typeface = fontManager->legacyCreateTypeface(family.utf8().data(), SkFontStyle());
 
     if (!typeface)
         return false;
diff --git a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
index 505b9a55..cdf81df 100644
--- a/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ContiguousContainer.cpp
@@ -6,9 +6,9 @@
 
 #include "wtf/Allocator.h"
 #include "wtf/ContainerAnnotations.h"
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassOwnPtr.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 #include <algorithm>
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp b/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
index 17e46a1..a80bd4e 100644
--- a/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
+++ b/third_party/WebKit/Source/platform/heap/CallbackStack.cpp
@@ -3,7 +3,7 @@
 // found in the LICENSE file.
 
 #include "platform/heap/CallbackStack.h"
-#include "wtf/PageAllocator.h"
+#include "wtf/allocator/PageAllocator.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/platform/heap/Heap.cpp b/third_party/WebKit/Source/platform/heap/Heap.cpp
index cb41196d..daf927f 100644
--- a/third_party/WebKit/Source/platform/heap/Heap.cpp
+++ b/third_party/WebKit/Source/platform/heap/Heap.cpp
@@ -49,7 +49,7 @@
 #include "wtf/CurrentTime.h"
 #include "wtf/DataLog.h"
 #include "wtf/LeakAnnotations.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.cpp b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
index f994e7e..7a580eb 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.cpp
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.cpp
@@ -47,9 +47,9 @@
 #include "wtf/ContainerAnnotations.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/LeakAnnotations.h"
-#include "wtf/PageAllocator.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassOwnPtr.h"
+#include "wtf/allocator/PageAllocator.h"
+#include "wtf/allocator/Partitions.h"
 
 #ifdef ANNOTATE_CONTIGUOUS_CONTAINER
 // FIXME: have ContainerAnnotations.h define an ENABLE_-style name instead.
diff --git a/third_party/WebKit/Source/platform/heap/HeapPage.h b/third_party/WebKit/Source/platform/heap/HeapPage.h
index bb54094..ce60de3 100644
--- a/third_party/WebKit/Source/platform/heap/HeapPage.h
+++ b/third_party/WebKit/Source/platform/heap/HeapPage.h
@@ -41,7 +41,7 @@
 #include "wtf/Assertions.h"
 #include "wtf/ContainerAnnotations.h"
 #include "wtf/Forward.h"
-#include "wtf/PageAllocator.h"
+#include "wtf/allocator/PageAllocator.h"
 #include <stdint.h>
 
 namespace blink {
diff --git a/third_party/WebKit/Source/platform/heap/PageMemory.cpp b/third_party/WebKit/Source/platform/heap/PageMemory.cpp
index ea53599..a01a2538 100644
--- a/third_party/WebKit/Source/platform/heap/PageMemory.cpp
+++ b/third_party/WebKit/Source/platform/heap/PageMemory.cpp
@@ -7,7 +7,7 @@
 #include "platform/heap/Heap.h"
 #include "wtf/Assertions.h"
 #include "wtf/Atomics.h"
-#include "wtf/PageAllocator.h"
+#include "wtf/allocator/PageAllocator.h"
 
 namespace blink {
 
diff --git a/third_party/WebKit/Source/platform/heap/PageMemory.h b/third_party/WebKit/Source/platform/heap/PageMemory.h
index ba2a5b7..314d501 100644
--- a/third_party/WebKit/Source/platform/heap/PageMemory.h
+++ b/third_party/WebKit/Source/platform/heap/PageMemory.h
@@ -8,7 +8,7 @@
 #include "platform/heap/HeapPage.h"
 #include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
-#include "wtf/PageAllocator.h"
+#include "wtf/allocator/PageAllocator.h"
 
 #if OS(POSIX)
 #include <sys/mman.h>
diff --git a/third_party/WebKit/Source/platform/heap/ThreadState.cpp b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
index 2e3bd22..873baa3 100644
--- a/third_party/WebKit/Source/platform/heap/ThreadState.cpp
+++ b/third_party/WebKit/Source/platform/heap/ThreadState.cpp
@@ -47,8 +47,8 @@
 #include "public/platform/WebTraceLocation.h"
 #include "wtf/CurrentTime.h"
 #include "wtf/DataLog.h"
-#include "wtf/Partitions.h"
 #include "wtf/ThreadingPrimitives.h"
+#include "wtf/allocator/Partitions.h"
 
 #if OS(WIN)
 #include <stddef.h>
diff --git a/third_party/WebKit/Source/platform/testing/RunAllTests.cpp b/third_party/WebKit/Source/platform/testing/RunAllTests.cpp
index 07b101c..01aec52 100644
--- a/third_party/WebKit/Source/platform/testing/RunAllTests.cpp
+++ b/third_party/WebKit/Source/platform/testing/RunAllTests.cpp
@@ -41,8 +41,8 @@
 #include "public/platform/Platform.h"
 #include "wtf/CryptographicallyRandomNumber.h"
 #include "wtf/CurrentTime.h"
-#include "wtf/Partitions.h"
 #include "wtf/WTF.h"
+#include "wtf/allocator/Partitions.h"
 #include <base/bind.h>
 #include <base/bind_helpers.h>
 #include <base/command_line.h>
diff --git a/third_party/WebKit/Source/platform/text/BidiCharacterRun.cpp b/third_party/WebKit/Source/platform/text/BidiCharacterRun.cpp
index ed7c581..f099629 100644
--- a/third_party/WebKit/Source/platform/text/BidiCharacterRun.cpp
+++ b/third_party/WebKit/Source/platform/text/BidiCharacterRun.cpp
@@ -23,7 +23,7 @@
 
 #include "platform/text/BidiCharacterRun.h"
 
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 using namespace WTF;
 
diff --git a/third_party/WebKit/Source/web/WebKit.cpp b/third_party/WebKit/Source/web/WebKit.cpp
index 52dbb64..f0ac13e62 100644
--- a/third_party/WebKit/Source/web/WebKit.cpp
+++ b/third_party/WebKit/Source/web/WebKit.cpp
@@ -44,8 +44,8 @@
 #include "public/platform/Platform.h"
 #include "public/platform/WebThread.h"
 #include "wtf/Assertions.h"
-#include "wtf/Partitions.h"
 #include "wtf/WTF.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/AtomicString.h"
 #include "wtf/text/TextEncoding.h"
 #include <v8.h>
diff --git a/third_party/WebKit/Source/wtf/Allocator.h b/third_party/WebKit/Source/wtf/Allocator.h
index 93e19fce..07921aca 100644
--- a/third_party/WebKit/Source/wtf/Allocator.h
+++ b/third_party/WebKit/Source/wtf/Allocator.h
@@ -6,8 +6,8 @@
 #define WTF_Allocator_h
 
 #include "wtf/Assertions.h"
-#include "wtf/Partitions.h"
 #include "wtf/StdLibExtras.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/BitVector.cpp b/third_party/WebKit/Source/wtf/BitVector.cpp
index 1ff094f..1523e4d 100644
--- a/third_party/WebKit/Source/wtf/BitVector.cpp
+++ b/third_party/WebKit/Source/wtf/BitVector.cpp
@@ -26,9 +26,9 @@
 #include "wtf/BitVector.h"
 
 #include "wtf/LeakAnnotations.h"
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
 #include "wtf/PrintStream.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 #include <algorithm>
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/wtf/HashMap.h b/third_party/WebKit/Source/wtf/HashMap.h
index ce558b48..8737cf1 100644
--- a/third_party/WebKit/Source/wtf/HashMap.h
+++ b/third_party/WebKit/Source/wtf/HashMap.h
@@ -22,7 +22,7 @@
 #define WTF_HashMap_h
 
 #include "wtf/HashTable.h"
-#include "wtf/PartitionAllocator.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/HashSet.h b/third_party/WebKit/Source/wtf/HashSet.h
index 3b38c17..7b57cbb 100644
--- a/third_party/WebKit/Source/wtf/HashSet.h
+++ b/third_party/WebKit/Source/wtf/HashSet.h
@@ -22,7 +22,7 @@
 #define WTF_HashSet_h
 
 #include "wtf/HashTable.h"
-#include "wtf/PartitionAllocator.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/HashTable.h b/third_party/WebKit/Source/wtf/HashTable.h
index 0226200c..a1b96bc 100644
--- a/third_party/WebKit/Source/wtf/HashTable.h
+++ b/third_party/WebKit/Source/wtf/HashTable.h
@@ -25,7 +25,7 @@
 #include "wtf/Assertions.h"
 #include "wtf/ConditionalDestructor.h"
 #include "wtf/HashTraits.h"
-#include "wtf/PartitionAllocator.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 #define DUMP_HASHTABLE_STATS 0
 #define DUMP_HASHTABLE_STATS_PER_TABLE 0
diff --git a/third_party/WebKit/Source/wtf/LinkedHashSet.h b/third_party/WebKit/Source/wtf/LinkedHashSet.h
index 1cb0e3c..d4bb0fb 100644
--- a/third_party/WebKit/Source/wtf/LinkedHashSet.h
+++ b/third_party/WebKit/Source/wtf/LinkedHashSet.h
@@ -25,8 +25,8 @@
 #include "wtf/AddressSanitizer.h"
 #include "wtf/HashSet.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/PartitionAllocator.h"
 #include "wtf/PassOwnPtr.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/ListHashSet.h b/third_party/WebKit/Source/wtf/ListHashSet.h
index 135c6b5..1afd63b 100644
--- a/third_party/WebKit/Source/wtf/ListHashSet.h
+++ b/third_party/WebKit/Source/wtf/ListHashSet.h
@@ -24,8 +24,8 @@
 
 #include "wtf/HashSet.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/PartitionAllocator.h"
 #include "wtf/PassOwnPtr.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/TerminatedArray.h b/third_party/WebKit/Source/wtf/TerminatedArray.h
index 6daba4bd..3134c258 100644
--- a/third_party/WebKit/Source/wtf/TerminatedArray.h
+++ b/third_party/WebKit/Source/wtf/TerminatedArray.h
@@ -6,7 +6,7 @@
 
 #include "wtf/Allocator.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/ThreadSpecific.h b/third_party/WebKit/Source/wtf/ThreadSpecific.h
index 2e82293b..f16836fe 100644
--- a/third_party/WebKit/Source/wtf/ThreadSpecific.h
+++ b/third_party/WebKit/Source/wtf/ThreadSpecific.h
@@ -44,10 +44,10 @@
 
 #include "wtf/Allocator.h"
 #include "wtf/Noncopyable.h"
-#include "wtf/Partitions.h"
 #include "wtf/StdLibExtras.h"
 #include "wtf/WTF.h"
 #include "wtf/WTFExport.h"
+#include "wtf/allocator/Partitions.h"
 
 #if OS(POSIX)
 #include <pthread.h>
diff --git a/third_party/WebKit/Source/wtf/Vector.h b/third_party/WebKit/Source/wtf/Vector.h
index 38715f66..0d55085 100644
--- a/third_party/WebKit/Source/wtf/Vector.h
+++ b/third_party/WebKit/Source/wtf/Vector.h
@@ -26,9 +26,9 @@
 #include "wtf/ContainerAnnotations.h"
 #include "wtf/Noncopyable.h"
 #include "wtf/NotFound.h"
-#include "wtf/PartitionAllocator.h"
 #include "wtf/StdLibExtras.h"
 #include "wtf/VectorTraits.h"
+#include "wtf/allocator/PartitionAllocator.h"
 #include <algorithm>
 #include <iterator>
 #include <string.h>
diff --git a/third_party/WebKit/Source/wtf/WTF.cpp b/third_party/WebKit/Source/wtf/WTF.cpp
index 5800e46..e064d14 100644
--- a/third_party/WebKit/Source/wtf/WTF.cpp
+++ b/third_party/WebKit/Source/wtf/WTF.cpp
@@ -32,8 +32,8 @@
 
 #include "wtf/Assertions.h"
 #include "wtf/Functional.h"
-#include "wtf/Partitions.h"
 #include "wtf/Threading.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/AtomicString.h"
 #include "wtf/text/StringStatics.h"
 #include "wtf/typed_arrays/ArrayBufferContents.h"
diff --git a/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp b/third_party/WebKit/Source/wtf/allocator/AddressSpaceRandomization.cpp
similarity index 97%
rename from third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp
rename to third_party/WebKit/Source/wtf/allocator/AddressSpaceRandomization.cpp
index fd52619..88d05e3 100644
--- a/third_party/WebKit/Source/wtf/AddressSpaceRandomization.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/AddressSpaceRandomization.cpp
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "wtf/AddressSpaceRandomization.h"
+#include "wtf/allocator/AddressSpaceRandomization.h"
 
-#include "wtf/PageAllocator.h"
 #include "wtf/SpinLock.h"
+#include "wtf/allocator/PageAllocator.h"
 
 #if OS(WIN)
 #include <windows.h>
diff --git a/third_party/WebKit/Source/wtf/AddressSpaceRandomization.h b/third_party/WebKit/Source/wtf/allocator/AddressSpaceRandomization.h
similarity index 100%
rename from third_party/WebKit/Source/wtf/AddressSpaceRandomization.h
rename to third_party/WebKit/Source/wtf/allocator/AddressSpaceRandomization.h
diff --git a/third_party/WebKit/Source/wtf/PageAllocator.cpp b/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/PageAllocator.cpp
rename to third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp
index d9b96f1..8546387 100644
--- a/third_party/WebKit/Source/wtf/PageAllocator.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/PageAllocator.cpp
@@ -28,10 +28,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/PageAllocator.h"
+#include "wtf/allocator/PageAllocator.h"
 
-#include "wtf/AddressSpaceRandomization.h"
 #include "wtf/Assertions.h"
+#include "wtf/allocator/AddressSpaceRandomization.h"
 
 #include <limits.h>
 
diff --git a/third_party/WebKit/Source/wtf/PageAllocator.h b/third_party/WebKit/Source/wtf/allocator/PageAllocator.h
similarity index 100%
rename from third_party/WebKit/Source/wtf/PageAllocator.h
rename to third_party/WebKit/Source/wtf/allocator/PageAllocator.h
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/PartitionAlloc.cpp
rename to third_party/WebKit/Source/wtf/allocator/PartitionAlloc.cpp
index a26147ab..11cf0eb 100644
--- a/third_party/WebKit/Source/wtf/PartitionAlloc.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/PartitionAlloc.h"
+#include "wtf/allocator/PartitionAlloc.h"
 
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.h b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h
similarity index 99%
rename from third_party/WebKit/Source/wtf/PartitionAlloc.h
rename to third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h
index 218484e..f84e9f3b 100644
--- a/third_party/WebKit/Source/wtf/PartitionAlloc.h
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.h
@@ -89,9 +89,9 @@
 #include "wtf/BitwiseOperations.h"
 #include "wtf/ByteSwap.h"
 #include "wtf/CPU.h"
-#include "wtf/PageAllocator.h"
 #include "wtf/SpinLock.h"
 #include "wtf/TypeTraits.h"
+#include "wtf/allocator/PageAllocator.h"
 
 #include <limits.h>
 
diff --git a/third_party/WebKit/Source/wtf/PartitionAlloc.md b/third_party/WebKit/Source/wtf/allocator/PartitionAlloc.md
similarity index 100%
rename from third_party/WebKit/Source/wtf/PartitionAlloc.md
rename to third_party/WebKit/Source/wtf/allocator/PartitionAlloc.md
diff --git a/third_party/WebKit/Source/wtf/PartitionAllocTest.cpp b/third_party/WebKit/Source/wtf/allocator/PartitionAllocTest.cpp
similarity index 99%
rename from third_party/WebKit/Source/wtf/PartitionAllocTest.cpp
rename to third_party/WebKit/Source/wtf/allocator/PartitionAllocTest.cpp
index e3ee87c..cdc4302 100644
--- a/third_party/WebKit/Source/wtf/PartitionAllocTest.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAllocTest.cpp
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/PartitionAlloc.h"
+#include "wtf/allocator/PartitionAlloc.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "wtf/BitwiseOperations.h"
diff --git a/third_party/WebKit/Source/wtf/PartitionAllocator.cpp b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.cpp
similarity index 94%
rename from third_party/WebKit/Source/wtf/PartitionAllocator.cpp
rename to third_party/WebKit/Source/wtf/allocator/PartitionAllocator.cpp
index e3d048ca..e4a357e 100644
--- a/third_party/WebKit/Source/wtf/PartitionAllocator.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.cpp
@@ -28,10 +28,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/PartitionAllocator.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/PartitionAllocator.h b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
similarity index 84%
rename from third_party/WebKit/Source/wtf/PartitionAllocator.h
rename to third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
index e3b57e5..2e0e0a9 100644
--- a/third_party/WebKit/Source/wtf/PartitionAllocator.h
+++ b/third_party/WebKit/Source/wtf/allocator/PartitionAllocator.h
@@ -37,14 +37,16 @@
 
 #include "wtf/Allocator.h"
 #include "wtf/Assertions.h"
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 
 #include <string.h>
 
 namespace WTF {
 
-class PartitionAllocatorDummyVisitor;
+class PartitionAllocatorDummyVisitor {
+    DISALLOW_NEW();
+};
 
 class WTF_EXPORT PartitionAllocator {
 public:
@@ -124,46 +126,6 @@
     }
 
     static bool isAllocationAllowed() { return true; }
-    template<typename T>
-    static bool isHeapObjectAlive(T* object)
-    {
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-
-    static void markNoTracing(...)
-    {
-        ASSERT_NOT_REACHED();
-    }
-
-    static void registerDelayedMarkNoTracing(...)
-    {
-        ASSERT_NOT_REACHED();
-    }
-
-    static void registerWeakMembers(...)
-    {
-        ASSERT_NOT_REACHED();
-    }
-
-    static void registerWeakTable(...)
-    {
-        ASSERT_NOT_REACHED();
-    }
-
-#if ENABLE(ASSERT)
-    static bool weakTableRegistered(...)
-    {
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-#endif
-
-    template<typename T, typename Traits>
-    static void trace(...)
-    {
-        ASSERT_NOT_REACHED();
-    }
 
     template<typename T>
     struct OtherType {
@@ -183,22 +145,10 @@
     static void* allocateBacking(size_t, const char* typeName);
 };
 
-// The Windows compiler seems to be very eager to instantiate things it won't
-// need, so unless we have this class we get compile errors.
-class PartitionAllocatorDummyVisitor {
-    DISALLOW_NEW();
-public:
-    template<typename T> inline bool isHeapObjectAlive(T obj)
-    {
-        ASSERT_NOT_REACHED();
-        return false;
-    }
-};
-
 // Specializations for heap profiling, so type profiling of |char| is possible
 // even in official builds (because |char| makes up a large portion of the heap.)
-template <> WTF_EXPORT char* PartitionAllocator::allocateVectorBacking<char>(size_t size);
-template <> WTF_EXPORT char* PartitionAllocator::allocateExpandedVectorBacking<char>(size_t size);
+template <> WTF_EXPORT char* PartitionAllocator::allocateVectorBacking<char>(size_t);
+template <> WTF_EXPORT char* PartitionAllocator::allocateExpandedVectorBacking<char>(size_t);
 
 } // namespace WTF
 
diff --git a/third_party/WebKit/Source/wtf/Partitions.cpp b/third_party/WebKit/Source/wtf/allocator/Partitions.cpp
similarity index 98%
rename from third_party/WebKit/Source/wtf/Partitions.cpp
rename to third_party/WebKit/Source/wtf/allocator/Partitions.cpp
index 73de42d..e7453599 100644
--- a/third_party/WebKit/Source/wtf/Partitions.cpp
+++ b/third_party/WebKit/Source/wtf/allocator/Partitions.cpp
@@ -28,10 +28,10 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include "wtf/Partitions.h"
+#include "wtf/allocator/Partitions.h"
 
 #include "base/debug/alias.h"
-#include "wtf/PartitionAllocator.h"
+#include "wtf/allocator/PartitionAllocator.h"
 
 namespace WTF {
 
diff --git a/third_party/WebKit/Source/wtf/Partitions.h b/third_party/WebKit/Source/wtf/allocator/Partitions.h
similarity index 98%
rename from third_party/WebKit/Source/wtf/Partitions.h
rename to third_party/WebKit/Source/wtf/allocator/Partitions.h
index dc9a4aa..e3a610d 100644
--- a/third_party/WebKit/Source/wtf/Partitions.h
+++ b/third_party/WebKit/Source/wtf/allocator/Partitions.h
@@ -31,9 +31,9 @@
 #ifndef Partitions_h
 #define Partitions_h
 
-#include "wtf/PartitionAlloc.h"
 #include "wtf/WTF.h"
 #include "wtf/WTFExport.h"
+#include "wtf/allocator/PartitionAlloc.h"
 #include <string.h>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp b/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp
index 65c81cb..2b5d15d 100644
--- a/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp
+++ b/third_party/WebKit/Source/wtf/testing/RunAllTests.cpp
@@ -30,8 +30,8 @@
 
 #include "wtf/CryptographicallyRandomNumber.h"
 #include "wtf/CurrentTime.h"
-#include "wtf/Partitions.h"
 #include "wtf/WTF.h"
+#include "wtf/allocator/Partitions.h"
 #include <base/test/test_suite.h>
 #include <string.h>
 
diff --git a/third_party/WebKit/Source/wtf/text/AtomicString.h b/third_party/WebKit/Source/wtf/text/AtomicString.h
index 9f79d42f..6fb8300 100644
--- a/third_party/WebKit/Source/wtf/text/AtomicString.h
+++ b/third_party/WebKit/Source/wtf/text/AtomicString.h
@@ -239,7 +239,8 @@
     typedef AtomicStringHash Hash;
 };
 
-// Pretty printer for gtest and base/logging.*.
+// Pretty printer for gtest and base/logging.*.  It prepends and appends
+// double-quotes, and escapes chracters other than ASCII printables.
 WTF_EXPORT std::ostream& operator<<(std::ostream&, const AtomicString&);
 
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/text/CString.cpp b/third_party/WebKit/Source/wtf/text/CString.cpp
index b3af14c..9d85026 100644
--- a/third_party/WebKit/Source/wtf/text/CString.cpp
+++ b/third_party/WebKit/Source/wtf/text/CString.cpp
@@ -26,8 +26,8 @@
 
 #include "wtf/text/CString.h"
 
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 #include <string.h>
 
 using namespace std;
diff --git a/third_party/WebKit/Source/wtf/text/StringImpl.cpp b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
index 3027cac..e91ac5a4 100644
--- a/third_party/WebKit/Source/wtf/text/StringImpl.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringImpl.cpp
@@ -27,10 +27,10 @@
 #include "wtf/DynamicAnnotations.h"
 #include "wtf/LeakAnnotations.h"
 #include "wtf/OwnPtr.h"
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
 #include "wtf/PassOwnPtr.h"
 #include "wtf/StdLibExtras.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 #include "wtf/text/AtomicString.h"
 #include "wtf/text/CharacterNames.h"
 #include "wtf/text/StringBuffer.h"
diff --git a/third_party/WebKit/Source/wtf/text/StringImplCF.cpp b/third_party/WebKit/Source/wtf/text/StringImplCF.cpp
index f6bd08dd..832e12c 100644
--- a/third_party/WebKit/Source/wtf/text/StringImplCF.cpp
+++ b/third_party/WebKit/Source/wtf/text/StringImplCF.cpp
@@ -22,10 +22,10 @@
 
 #if OS(MACOSX)
 
-#include "wtf/Partitions.h"
 #include "wtf/PassRefPtr.h"
 #include "wtf/RetainPtr.h"
 #include "wtf/Threading.h"
+#include "wtf/allocator/Partitions.h"
 #include <CoreFoundation/CoreFoundation.h>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/text/WTFString.h b/third_party/WebKit/Source/wtf/text/WTFString.h
index 4fada8e..8d01437 100644
--- a/third_party/WebKit/Source/wtf/text/WTFString.h
+++ b/third_party/WebKit/Source/wtf/text/WTFString.h
@@ -678,7 +678,8 @@
 WTF_EXPORT const String& emptyString16Bit();
 WTF_EXPORT extern const String& xmlnsWithColon;
 
-// Pretty printer for gtest and base/logging.*.
+// Pretty printer for gtest and base/logging.*.  It prepends and appends
+// double-quotes, and escapes chracters other than ASCII printables.
 WTF_EXPORT std::ostream& operator<<(std::ostream&, const String&);
 
 } // namespace WTF
diff --git a/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferContents.cpp b/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferContents.cpp
index f2a1780..7c39972 100644
--- a/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferContents.cpp
+++ b/third_party/WebKit/Source/wtf/typed_arrays/ArrayBufferContents.cpp
@@ -27,8 +27,8 @@
 #include "wtf/typed_arrays/ArrayBufferContents.h"
 
 #include "wtf/Assertions.h"
-#include "wtf/PartitionAlloc.h"
-#include "wtf/Partitions.h"
+#include "wtf/allocator/PartitionAlloc.h"
+#include "wtf/allocator/Partitions.h"
 #include <string.h>
 
 namespace WTF {
diff --git a/third_party/WebKit/Source/wtf/wtf.gypi b/third_party/WebKit/Source/wtf/wtf.gypi
index 399f003..fe778a0 100644
--- a/third_party/WebKit/Source/wtf/wtf.gypi
+++ b/third_party/WebKit/Source/wtf/wtf.gypi
@@ -5,8 +5,6 @@
             'ASCIICType.cpp',
             'ASCIICType.h',
             'AddressSanitizer.h',
-            'AddressSpaceRandomization.cpp',
-            'AddressSpaceRandomization.h',
             'Alignment.h',
             'Allocator.h',
             'Assertions.cpp',
@@ -63,14 +61,6 @@
             'Optional.h',
             'OwnPtr.h',
             'OwnPtrCommon.h',
-            'PageAllocator.cpp',
-            'PageAllocator.h',
-            'PartitionAlloc.cpp',
-            'PartitionAlloc.h',
-            'PartitionAllocator.cpp',
-            'PartitionAllocator.h',
-            'Partitions.cpp',
-            'Partitions.h',
             'PassOwnPtr.h',
             'PassRefPtr.h',
             'PrintStream.cpp',
@@ -106,6 +96,16 @@
             'WTFThreadData.cpp',
             'WTFThreadData.h',
             'WeakPtr.h',
+            'allocator/AddressSpaceRandomization.cpp',
+            'allocator/AddressSpaceRandomization.h',
+            'allocator/PageAllocator.cpp',
+            'allocator/PageAllocator.h',
+            'allocator/PartitionAlloc.cpp',
+            'allocator/PartitionAlloc.h',
+            'allocator/PartitionAllocator.cpp',
+            'allocator/PartitionAllocator.h',
+            'allocator/Partitions.cpp',
+            'allocator/Partitions.h',
             'asm/SaturatedArithmeticARM.h',
             'build_config.h',
             'dtoa.cpp',
@@ -207,7 +207,6 @@
             'ListHashSetTest.cpp',
             'MathExtrasTest.cpp',
             'OptionalTest.cpp',
-            'PartitionAllocTest.cpp',
             'RefPtrTest.cpp',
             'SaturatedArithmeticTest.cpp',
             'StringExtrasTest.cpp',
@@ -216,6 +215,7 @@
             'TreeNodeTest.cpp',
             'TypeTraitsTest.cpp',
             'VectorTest.cpp',
+            'allocator/PartitionAllocTest.cpp',
             'dtoa_test.cpp',
             'text/AtomicStringTest.cpp',
             'text/CStringTest.cpp',
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index 0d1ff42..37f531e2 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -510,7 +510,7 @@
       'WebKit Mac10.11 (dbg)': 'none',
       'WebKit Mac10.11 (retina)': 'swarming_gyp_release_bot_x64',
       'WebKit Mac10.11': 'none',
-      'WebKit Mac10.9': 'none',
+      'WebKit Mac10.9': 'swarming_gyp_release_bot_x64',
       'WebKit Win Builder (dbg)': 'swarming_gyp_debug_bot_minimal_symbols_x86',
       'WebKit Win Builder': 'swarming_gyp_release_bot_minimal_symbols_x86',
       'WebKit Win x64 Builder (dbg)':
@@ -1567,14 +1567,11 @@
     # Removes dependencies on X11 and audio libraries for a containerized
     # build.
     'blimp': {
-      # 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',
+      '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'),
     },
 
     'cast': {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 57a5ea16..f2ab34e 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -74959,6 +74959,7 @@
   <int value="-1172204005" label="enable-offline-auto-reload-visible-only"/>
   <int value="-1160026273" label="enable-web-notification-custom-layouts"/>
   <int value="-1159563774" label="enable-accessibility-script-injection"/>
+  <int value="-1151766565" label="enable-fullscreen-tab-detaching"/>
   <int value="-1137442543" label="enable-slimming-paint"/>
   <int value="-1136627751" label="ignore-autocomplete-off-autofill"/>
   <int value="-1136509631" label="ssl-interstitial-v1"/>
diff --git a/tools/perf/core/stacktrace_unittest.py b/tools/perf/core/stacktrace_unittest.py
index 9ab0625..3c5392933 100644
--- a/tools/perf/core/stacktrace_unittest.py
+++ b/tools/perf/core/stacktrace_unittest.py
@@ -46,7 +46,7 @@
                                      dir=os.path.dirname(executable_path),
                                      prefix=executable + '.breakpad',
                                      delete=True) as f:
-      # Do not write anything to file, it will just be an invalid empty file.
+      f.write('Garbage Data 012345')
       f.flush()
       with self.assertRaises(exceptions.DevtoolsTargetCrashException) as c:
         self._tab.Navigate('chrome://crash', timeout=5)
diff --git a/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py b/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
index 5e3442eb..42e5330 100644
--- a/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
+++ b/tools/perf/measurements/v8_detached_context_age_in_gc_unittest.py
@@ -11,11 +11,14 @@
 from measurements import v8_detached_context_age_in_gc
 
 
-class FakePage(object):
+class FakePage(page_module.Page):
 
   def __init__(self, url):
-    self.url = url
-    self.is_file = url.startswith('file://')
+    super(FakePage, self).__init__(url=url)
+
+  @property
+  def is_file(self):
+    return self._url.startswith('file://')
 
 
 class FakeTab(object):
diff --git a/tools/perf/page_sets/pregenerated_large_profile_shared_state.py b/tools/perf/page_sets/pregenerated_large_profile_shared_state.py
index 6edd1ee..3f81b3a 100644
--- a/tools/perf/page_sets/pregenerated_large_profile_shared_state.py
+++ b/tools/perf/page_sets/pregenerated_large_profile_shared_state.py
@@ -3,17 +3,16 @@
 # found in the LICENSE file.
 import os
 
-from telemetry.page import shared_page_state
+from page_sets import pregenerated_profile_shared_state
 
 
-class PregeneratedLargeProfileSharedState(shared_page_state.SharedPageState):
+class PregeneratedLargeProfileSharedState(
+    pregenerated_profile_shared_state.PregeneratedProfileSharedState):
   def __init__(self, test, finder_options, story_set):
     super(PregeneratedLargeProfileSharedState, self).__init__(
         test, finder_options, story_set)
     perf_dir = os.path.normpath(
         os.path.join(os.path.dirname(__file__), os.path.pardir))
-    profile_archive_dir = os.path.join(
+    self._pregenerated_profile_archive_dir = os.path.join(
         perf_dir, 'generated_profiles', self._possible_browser.target_os,
         'large_profile.zip')
-
-    self.SetPregeneratedProfileArchiveDir(profile_archive_dir)
diff --git a/tools/perf/page_sets/pregenerated_profile_shared_state.py b/tools/perf/page_sets/pregenerated_profile_shared_state.py
new file mode 100644
index 0000000..879c219
--- /dev/null
+++ b/tools/perf/page_sets/pregenerated_profile_shared_state.py
@@ -0,0 +1,157 @@
+# 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 logging
+import os
+import shutil
+import sys
+import tempfile
+import zipfile
+
+from catapult_base import cloud_storage
+
+from telemetry.page import shared_page_state
+
+
+class PregeneratedProfileSharedState(shared_page_state.SharedPageState):
+  def __init__(self, test, finder_options, story_set):
+    super(PregeneratedProfileSharedState, self).__init__(
+        test, finder_options, story_set)
+    self._unzipped_profile = None
+    self._migrated_profile = None
+    self._pregenerated_profile_archive_dir = None
+
+  def WillRunStory(self, page):
+    if self._ShouldDownloadPregeneratedProfileArchive():
+      self._DownloadPregeneratedProfileArchive()
+
+      if self._ShouldMigrateProfile():
+        self._MigratePregeneratedProfile()
+    super(PregeneratedProfileSharedState, self).WillRunStory(page)
+
+  def TearDownState(self):
+    if self._unzipped_profile:
+      shutil.rmtree(self._unzipped_profile)
+      self._unzipped_profile = None
+    if self._migrated_profile:
+      shutil.rmtree(self._migrated_profile)
+      self._migrated_profile = None
+    super(PregeneratedProfileSharedState, self).TearDownState()
+
+  def _ShouldDownloadPregeneratedProfileArchive(self):
+    """Whether to download a pre-generated profile archive."""
+    if not self._pregenerated_profile_archive_dir:
+      return False
+
+    if self._finder_options.browser_options.profile_dir:
+      logging.warning("Profile directory specified on command line: %s, this"
+                      "overrides the benchmark's default profile directory.",
+                      self._finder_options.browser_options.profile_dir)
+      return False
+
+    if self._possible_browser.IsRemote():
+      return False
+
+    return True
+
+  def _DownloadPregeneratedProfileArchive(self):
+    """Download and extract the profile directory archive if one exists.
+
+    On success, updates self._finder_options.browser_options.profile_dir with
+    the directory of the extracted profile.
+    """
+    try:
+      cloud_storage.GetIfChanged(self._pregenerated_profile_archive_dir,
+                                 cloud_storage.PUBLIC_BUCKET)
+    except (cloud_storage.CredentialsError,
+            cloud_storage.PermissionError) as e:
+      if os.path.exists(self._pregenerated_profile_archive_path):
+        # If the profile directory archive exists, assume the user has their
+        # own local copy simply warn.
+        logging.warning('Could not download Profile archive: %s',
+                        self._pregenerated_profile_archive_dir)
+      else:
+        # If the archive profile directory doesn't exist, this is fatal.
+        logging.error('Can not run without required profile archive: %s. '
+                      'If you believe you have credentials, follow the '
+                      'instructions below.',
+                      self._pregenerated_profile_archive_path)
+        logging.error(str(e))
+        sys.exit(-1)
+
+    # Check to make sure the zip file exists.
+    if not os.path.isfile(self._pregenerated_profile_archive_path):
+      raise Exception("Profile directory archive not downloaded: ",
+                      self._pregenerated_profile_archive_path)
+
+    # The location to extract the profile into.
+    self._unzipped_profile = tempfile.mkdtemp()
+    profile_archive_path_basename = os.path.basename(
+        self._pregenerated_profile_archive_path)
+    extracted_profile_dir_path = os.path.join(
+        self._unzipped_profile,
+        os.path.splitext(profile_archive_path_basename)[0])
+
+    # Unzip profile directory.
+    with zipfile.ZipFile(self._pregenerated_profile_archive_path) as f:
+      try:
+        f.extractall(self._unzipped_profile)
+      except Exception as e:
+        # Cleanup any leftovers from unzipping.
+        shutil.rmtree(self._unzipped_profile)
+        logging.error("Error extracting profile directory zip file: %s", e)
+        sys.exit(-1)
+
+    if not os.path.exists(extracted_profile_dir_path):
+      raise Exception("Failed to extract profile: ",
+                      extracted_profile_dir_path)
+
+    # Run with freshly extracted profile directory.
+    logging.info("Using profile archive directory: %s",
+                 extracted_profile_dir_path)
+    self._finder_options.browser_options.profile_dir = (
+        extracted_profile_dir_path)
+
+  def _ShouldMigrateProfile(self):
+    return not self._migrated_profile
+
+  def _MigrateProfile(self, finder_options, found_browser,
+                      initial_profile, final_profile):
+    """Migrates a profile to be compatible with a newer version of Chrome.
+
+    Launching Chrome with the old profile will perform the migration.
+    """
+    # Save the current input and output profiles.
+    saved_input_profile = finder_options.browser_options.profile_dir
+    saved_output_profile = finder_options.browser_options.output_profile_path
+
+    # Set the input and output profiles.
+    finder_options.browser_options.profile_dir = initial_profile
+    finder_options.browser_options.output_profile_path = final_profile
+
+    # Launch the browser, then close it.
+    browser = found_browser.Create(finder_options)
+    browser.Close()
+
+    # Load the saved input and output profiles.
+    finder_options.browser_options.profile_dir = saved_input_profile
+    finder_options.browser_options.output_profile_path = saved_output_profile
+
+  def _MigratePregeneratedProfile(self):
+    """Migrates the pre-generated profile by launching Chrome with it.
+
+    On success, updates self._migrated_profile and
+    self._finder_options.browser_options.profile_dir with the directory of the
+    migrated profile.
+    """
+    self._migrated_profile = tempfile.mkdtemp()
+    logging.info("Starting migration of pre-generated profile to %s",
+                 self._migrated_profile)
+    pregenerated_profile = self._finder_options.browser_options.profile_dir
+
+    possible_browser = self._FindBrowser(self._finder_options)
+    self._MigrateProfile(self._finder_options, possible_browser,
+                         pregenerated_profile, self._migrated_profile)
+    self._finder_options.browser_options.profile_dir = self._migrated_profile
+    logging.info("Finished migration of pre-generated profile to %s",
+                 self._migrated_profile)
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn
index 21eecf0b..20b75f2 100644
--- a/ui/events/BUILD.gn
+++ b/ui/events/BUILD.gn
@@ -54,6 +54,8 @@
     "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" ]
@@ -149,7 +151,6 @@
     "//skia",
     "//ui/gfx",
     "//ui/gfx/geometry",
-    "//ui/latency_info",
   ]
 
   if (use_x11) {
@@ -367,6 +368,7 @@
     "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",
@@ -387,7 +389,6 @@
     "//ui/events/devices",
     "//ui/events/platform",
     "//ui/gfx:test_support",
-    "//ui/latency_info",
   ]
 
   if (!is_ios) {
@@ -395,6 +396,7 @@
       "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",
@@ -402,6 +404,7 @@
       "//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 8a18605..b273ae3 100644
--- a/ui/events/DEPS
+++ b/ui/events/DEPS
@@ -1,4 +1,3 @@
 include_rules = [
   "+ui/gfx",
-  "+ui/latency_info",
 ]
diff --git a/ui/events/OWNERS b/ui/events/OWNERS
index 1c0edbda..f14df80fd 100644
--- a/ui/events/OWNERS
+++ b/ui/events/OWNERS
@@ -1,4 +1,7 @@
 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 c347d9b..8b1b8fa 100644
--- a/ui/events/blink/events_blink.gyp
+++ b/ui/events/blink/events_blink.gyp
@@ -15,7 +15,6 @@
         '../../../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',
       ],
@@ -32,4 +31,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 bc494871..2d9eefb 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 729029b..2ef91cd 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 07416945..5c1b108 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 8c814d3..c8d994f 100644
--- a/ui/events/events.gyp
+++ b/ui/events/events.gyp
@@ -66,6 +66,8 @@
         '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',
       ],
@@ -98,7 +100,6 @@
         '<(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',
@@ -300,6 +301,24 @@
       ],
     },
     {
+      # 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 0665b33..f5a5d01c 100644
--- a/ui/events/events_unittests.gyp
+++ b/ui/events/events_unittests.gyp
@@ -26,6 +26,7 @@
         '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',
@@ -53,9 +54,11 @@
         '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/latency_info/ipc/BUILD.gn b/ui/events/ipc/BUILD.gn
similarity index 68%
rename from ui/latency_info/ipc/BUILD.gn
rename to ui/events/ipc/BUILD.gn
index 411305d..b6ccbf5 100644
--- a/ui/latency_info/ipc/BUILD.gn
+++ b/ui/events/ipc/BUILD.gn
@@ -2,23 +2,21 @@
 # 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 = "latency_info_ipc"
+  output_name = "events_ipc"
   sources = [
-    "latency_info_ipc_export.h",
     "latency_info_param_traits.cc",
     "latency_info_param_traits.h",
     "latency_info_param_traits_macros.h",
   ]
 
-  defines = [ "LATENCY_INFO_IPC_IMPLEMENTATION" ]
-
-  public_deps = [
-    "//ui/latency_info",
-  ]
+  defines = [ "EVENTS_IPC_IMPLEMENTATION" ]
 
   deps = [
     "//base",
     "//ipc",
+    "//ui/events:events_base",
   ]
 }
diff --git a/ui/events/ipc/OWNERS b/ui/events/ipc/OWNERS
new file mode 100644
index 0000000..6732300
--- /dev/null
+++ b/ui/events/ipc/OWNERS
@@ -0,0 +1,12 @@
+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
new file mode 100644
index 0000000..a02d669
--- /dev/null
+++ b/ui/events/ipc/events_ipc_export.h
@@ -0,0 +1,29 @@
+// 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/latency_info/ipc/latency_info_param_traits.cc b/ui/events/ipc/latency_info_param_traits.cc
similarity index 77%
rename from ui/latency_info/ipc/latency_info_param_traits.cc
rename to ui/events/ipc/latency_info_param_traits.cc
index 22785fcf..a4723074 100644
--- a/ui/latency_info/ipc/latency_info_param_traits.cc
+++ b/ui/events/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/latency_info/ipc/latency_info_param_traits_macros.h"
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
 
 // Generate param traits write methods.
 #include "ipc/param_traits_write_macros.h"
 namespace IPC {
-#undef UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/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_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/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_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
+#undef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#include "ui/events/ipc/latency_info_param_traits_macros.h"
 }  // namespace IPC
 
 // Implemetation for ParamTraits<ui::LatencyInfo>.
-#include "ui/latency_info/ipc/latency_info_param_traits.h"
+#include "ui/events/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,7 +67,8 @@
   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/events/ipc/latency_info_param_traits.h b/ui/events/ipc/latency_info_param_traits.h
new file mode 100644
index 0000000..9e11104
--- /dev/null
+++ b/ui/events/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_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/latency_info/ipc/latency_info_param_traits_macros.h b/ui/events/ipc/latency_info_param_traits_macros.h
similarity index 66%
rename from ui/latency_info/ipc/latency_info_param_traits_macros.h
rename to ui/events/ipc/latency_info_param_traits_macros.h
index 2539d92..40bf738 100644
--- a/ui/latency_info/ipc/latency_info_param_traits_macros.h
+++ b/ui/events/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_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
-#define UI_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#ifndef UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#define UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
 
 #include "ipc/ipc_message_macros.h"
-#include "ui/latency_info/ipc/latency_info_ipc_export.h"
-#include "ui/latency_info/latency_info.h"
+#include "ui/events/ipc/events_ipc_export.h"
+#include "ui/events/latency_info.h"
 
 #undef IPC_MESSAGE_EXPORT
-#define IPC_MESSAGE_EXPORT LATENCY_INFO_IPC_EXPORT
+#define IPC_MESSAGE_EXPORT EVENTS_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_LATENCY_INFO_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
+#endif // UI_EVENTS_IPC_LATENCY_INFO_PARAM_TRAITS_MACROS_H_
diff --git a/ui/latency_info/ipc/latency_info_param_traits_unittest.cc b/ui/events/ipc/latency_info_param_traits_unittest.cc
similarity index 84%
rename from ui/latency_info/ipc/latency_info_param_traits_unittest.cc
rename to ui/events/ipc/latency_info_param_traits_unittest.cc
index 4a1f8dc..69224dac 100644
--- a/ui/latency_info/ipc/latency_info_param_traits_unittest.cc
+++ b/ui/events/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/latency_info/ipc/latency_info_param_traits.h"
-#include "ui/latency_info/ipc/latency_info_param_traits_macros.h"
+#include "ui/events/ipc/latency_info_param_traits.h"
+#include "ui/events/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,11 +48,13 @@
               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/latency_info/latency_info.cc b/ui/events/latency_info.cc
similarity index 81%
rename from ui/latency_info/latency_info.cc
rename to ui/events/latency_info.cc
index 66e3748..b5d9954 100644
--- a/ui/latency_info/latency_info.cc
+++ b/ui/events/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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 #include <stddef.h>
 
@@ -20,9 +20,7 @@
 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);
@@ -106,7 +104,8 @@
       new LatencyInfoTracedValue(value.release()));
 }
 
-LatencyInfoTracedValue::~LatencyInfoTracedValue() {}
+LatencyInfoTracedValue::~LatencyInfoTracedValue() {
+}
 
 void LatencyInfoTracedValue::AppendAsTraceFormat(std::string* out) const {
   std::string tmp;
@@ -115,28 +114,32 @@
 }
 
 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),
@@ -159,7 +162,8 @@
     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;
@@ -169,9 +173,11 @@
                                   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);
     }
   }
 }
@@ -179,9 +185,11 @@
 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);
     }
   }
 }
@@ -235,9 +243,12 @@
       // 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();
@@ -251,13 +262,17 @@
       }
 
       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);
@@ -266,15 +281,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;
     }
   }
@@ -285,13 +300,15 @@
     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);
   }
@@ -306,9 +323,11 @@
         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));
   }
@@ -332,8 +351,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/latency_info/latency_info.dot b/ui/events/latency_info.dot
similarity index 100%
rename from ui/latency_info/latency_info.dot
rename to ui/events/latency_info.dot
diff --git a/ui/latency_info/latency_info.h b/ui/events/latency_info.h
similarity index 95%
rename from ui/latency_info/latency_info.h
rename to ui/events/latency_info.h
index 880b4adf..22e1ab4 100644
--- a/ui/latency_info/latency_info.h
+++ b/ui/events/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_LATENCY_INFO_LATENCY_INFO_H_
-#define UI_LATENCY_INFO_LATENCY_INFO_H_
+#ifndef UI_EVENTS_LATENCY_INFO_H_
+#define UI_EVENTS_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/latency_info/latency_info_export.h"
+#include "ui/events/events_base_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 LATENCY_INFO_EXPORT LatencyInfo {
+class EVENTS_BASE_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 LATENCY_INFO_EXPORT InputCoordinate {
+  struct EVENTS_BASE_EXPORT InputCoordinate {
     InputCoordinate();
     InputCoordinate(float x, float y);
 
@@ -130,8 +130,7 @@
   // component info.
   typedef base::SmallMap<
       std::map<std::pair<LatencyComponentType, int64_t>, LatencyComponent>,
-      kTypicalMaxComponentsPerLatencyInfo>
-      LatencyMap;
+      kTypicalMaxComponentsPerLatencyInfo> LatencyMap;
 
   LatencyInfo();
   LatencyInfo(const LatencyInfo& other);
@@ -241,4 +240,4 @@
 
 }  // namespace ui
 
-#endif  // UI_LATENCY_INFO_LATENCY_INFO_H_
+#endif  // UI_EVENTS_LATENCY_INFO_H_
diff --git a/ui/latency_info/latency_info_unittest.cc b/ui/events/latency_info_unittest.cc
similarity index 98%
rename from ui/latency_info/latency_info_unittest.cc
rename to ui/events/latency_info_unittest.cc
index 1d17863a..e279863 100644
--- a/ui/latency_info/latency_info_unittest.cc
+++ b/ui/events/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/latency_info/latency_info.h"
+#include "ui/events/latency_info.h"
 
 #include <stddef.h>
 
diff --git a/ui/latency_info/BUILD.gn b/ui/latency_info/BUILD.gn
deleted file mode 100644
index ad8f8c152..0000000
--- a/ui/latency_info/BUILD.gn
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-import("//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
deleted file mode 100644
index b29cc1a..0000000
--- a/ui/latency_info/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-tdresser@chromium.org
diff --git a/ui/latency_info/ipc/OWNERS b/ui/latency_info/ipc/OWNERS
deleted file mode 100644
index 107c401..0000000
--- a/ui/latency_info/ipc/OWNERS
+++ /dev/null
@@ -1,13 +0,0 @@
-# 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
deleted file mode 100644
index cf80d5fd..0000000
--- a/ui/latency_info/ipc/latency_info_ipc_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef 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/latency_info/ipc/latency_info_param_traits.h b/ui/latency_info/ipc/latency_info_param_traits.h
deleted file mode 100644
index 4bfdc6e..0000000
--- a/ui/latency_info/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_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/latency_info/latency_info.gyp b/ui/latency_info/latency_info.gyp
deleted file mode 100644
index ce7f05f..0000000
--- a/ui/latency_info/latency_info.gyp
+++ /dev/null
@@ -1,46 +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.
-
-{
-  '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/latency_info/latency_info_export.h b/ui/latency_info/latency_info_export.h
deleted file mode 100644
index 864c966..0000000
--- a/ui/latency_info/latency_info_export.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef 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/latency_info/latency_info_unittests.gyp b/ui/latency_info/latency_info_unittests.gyp
deleted file mode 100644
index d2c9d54..0000000
--- a/ui/latency_info/latency_info_unittests.gyp
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-{
-  '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/views.gyp b/ui/views/views.gyp
index 837d206..43f4ac3 100644
--- a/ui/views/views.gyp
+++ b/ui/views/views.gyp
@@ -671,7 +671,6 @@
         '../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',