diff --git a/DEPS b/DEPS
index 94476aa..1b90e811 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '9fd55f76d82496ca9233bd180f69152ff14b6613',
+  'v8_revision': '170a71e43122d2f7aa8300433e33ca4782349fd7',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/ash/accelerators/accelerator_controller_unittest.cc b/ash/accelerators/accelerator_controller_unittest.cc
index 650336b0..58b8e588 100644
--- a/ash/accelerators/accelerator_controller_unittest.cc
+++ b/ash/accelerators/accelerator_controller_unittest.cc
@@ -1124,15 +1124,9 @@
   EXPECT_TRUE(test_api.is_animating_lock());
 #endif
 
-  auto press_and_release_alt_tab = [&generator]() {
-    generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
-    // Release the alt key to trigger the window activation.
-    generator.ReleaseKey(ui::VKEY_MENU, ui::EF_NONE);
-  };
-
   // A fullscreen window can consume ALT-TAB (preferred).
   ASSERT_EQ(w1, wm::GetActiveWindow());
-  press_and_release_alt_tab();
+  generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
   ASSERT_EQ(w1, wm::GetActiveWindow());
   ASSERT_NE(w2, wm::GetActiveWindow());
 
@@ -1147,7 +1141,7 @@
   ASSERT_FALSE(w1_state->IsFullscreen());
 
   EXPECT_EQ(w1, wm::GetActiveWindow());
-  press_and_release_alt_tab();
+  generator.PressKey(ui::VKEY_TAB, ui::EF_ALT_DOWN);
   ASSERT_NE(w1, wm::GetActiveWindow());
   ASSERT_EQ(w2, wm::GetActiveWindow());
 }
diff --git a/ash/common/ash_switches.cc b/ash/common/ash_switches.cc
index ee32e4b3..1e45a7e 100644
--- a/ash/common/ash_switches.cc
+++ b/ash/common/ash_switches.cc
@@ -78,6 +78,9 @@
 // removed.
 const char kAshEnableTouchViewTesting[] = "ash-enable-touch-view-testing";
 
+// Enables the window cycling UI (more visual feedback for alt-tab).
+const char kAshEnableWindowCycleUi[] = "ash-enable-window-cycle-ui";
+
 // Hides notifications that are irrelevant to Chrome OS device factory testing,
 // such as battery level updates.
 const char kAshHideNotificationsForFactory[] =
diff --git a/ash/common/ash_switches.h b/ash/common/ash_switches.h
index 2d19523..21617aa 100644
--- a/ash/common/ash_switches.h
+++ b/ash/common/ash_switches.h
@@ -38,6 +38,7 @@
 ASH_EXPORT extern const char kAshEnableStableOverviewOrder[];
 ASH_EXPORT extern const char kAshEnableSoftwareMirroring[];
 ASH_EXPORT extern const char kAshEnableTouchViewTesting[];
+ASH_EXPORT extern const char kAshEnableWindowCycleUi[];
 ASH_EXPORT extern const char kAshHideNotificationsForFactory[];
 ASH_EXPORT extern const char kAshHostWindowBounds[];
 ASH_EXPORT extern const char kAshMaterialDesign[];
diff --git a/ash/common/wm/window_cycle_controller.cc b/ash/common/wm/window_cycle_controller.cc
index 4808148..6135f600 100644
--- a/ash/common/wm/window_cycle_controller.cc
+++ b/ash/common/wm/window_cycle_controller.cc
@@ -6,12 +6,10 @@
 
 #include "ash/common/metrics/task_switch_source.h"
 #include "ash/common/session/session_state_delegate.h"
-#include "ash/common/shell_window_ids.h"
 #include "ash/common/wm/mru_window_tracker.h"
 #include "ash/common/wm/window_cycle_event_filter.h"
 #include "ash/common/wm/window_cycle_list.h"
 #include "ash/common/wm_shell.h"
-#include "ash/common/wm_window.h"
 #include "base/metrics/histogram.h"
 
 namespace ash {
@@ -54,19 +52,6 @@
 void WindowCycleController::StartCycling() {
   MruWindowTracker::WindowList window_list =
       WmShell::Get()->mru_window_tracker()->BuildMruWindowList();
-  // Exclude the AppList window, which will hide as soon as cycling starts
-  // anyway. It doesn't make sense to count it as a "switchable" window, yet
-  // a lot of code relies on the MRU list returning the app window. If we
-  // don't manually remove it, the window cycling UI won't crash or misbehave,
-  // but there will be a flicker as the target window changes.
-  window_list.erase(std::remove_if(window_list.begin(), window_list.end(),
-                                   [](WmWindow* window) {
-                                     return window->GetRootWindow()
-                                         ->GetChildByShellWindowId(
-                                             kShellWindowId_AppListContainer)
-                                         ->Contains(window);
-                                   }),
-                    window_list.end());
 
   active_window_before_window_cycle_ = GetActiveWindow(window_list);
 
diff --git a/ash/common/wm/window_cycle_list.cc b/ash/common/wm/window_cycle_list.cc
index 845dcaa..2c0ec797 100644
--- a/ash/common/wm/window_cycle_list.cc
+++ b/ash/common/wm/window_cycle_list.cc
@@ -30,10 +30,6 @@
 
 namespace ash {
 
-namespace {
-
-bool g_disable_initial_delay = false;
-
 // Returns the window immediately below |window| in the current container.
 WmWindow* GetWindowBelow(WmWindow* window) {
   WmWindow* parent = window->GetParent();
@@ -65,8 +61,6 @@
   DISALLOW_COPY_AND_ASSIGN(LayerFillBackgroundPainter);
 };
 
-}  // namespace
-
 // This class restores and moves a window to the front of the stacking order for
 // the duration of the class's scope.
 class ScopedShowWindow : public WmWindowObserver {
@@ -308,28 +302,16 @@
     target_window_ = target;
     if (GetWidget()) {
       Layout();
-      if (target_window_) {
-        // In the window destruction case, we may have already removed the
-        // focused view and hence not be the focused window. We should still
-        // always be active, though.
-        DCHECK_EQ(ash::WmShell::Get()->GetActiveWindow()->GetInternalWidget(),
-                  GetWidget());
-        window_view_map_[target_window_]->RequestFocus();
-      }
+      DCHECK(Contains(GetFocusManager()->GetFocusedView()));
+      window_view_map_[target_window_]->RequestFocus();
     }
   }
 
   void HandleWindowDestruction(WmWindow* destroying_window,
                                WmWindow* new_target) {
     auto view_iter = window_view_map_.find(destroying_window);
-    views::View* parent = view_iter->second->parent();
-    DCHECK_EQ(mirror_container_, parent);
-    parent->RemoveChildView(view_iter->second);
+    view_iter->second->parent()->RemoveChildView(view_iter->second);
     window_view_map_.erase(view_iter);
-    // With one of its children now gone, we must re-layout |mirror_container_|.
-    // This must happen before SetTargetWindow() to make sure our own Layout()
-    // works correctly when it's calculating highlight bounds.
-    parent->Layout();
     SetTargetWindow(new_target);
   }
 
@@ -433,26 +415,19 @@
 
 WindowCycleList::WindowCycleList(const WindowList& windows)
     : windows_(windows), current_index_(0), cycle_view_(nullptr) {
-  if (!ShouldShowUi())
-    WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(true);
+  WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(true);
 
   for (WmWindow* window : windows_)
     window->AddObserver(this);
 
   if (ShouldShowUi()) {
-    if (g_disable_initial_delay) {
-      InitWindowCycleView();
-    } else {
-      show_ui_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150),
-                           this, &WindowCycleList::InitWindowCycleView);
-    }
+    show_ui_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(150),
+                         this, &WindowCycleList::InitWindowCycleView);
   }
 }
 
 WindowCycleList::~WindowCycleList() {
-  if (!ShouldShowUi())
-    WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(false);
-
+  WmShell::Get()->mru_window_tracker()->SetIgnoreActivations(false);
   for (WmWindow* window : windows_)
     window->RemoveObserver(this);
 
@@ -500,11 +475,6 @@
   }
 }
 
-// static
-void WindowCycleList::DisableInitialDelayForTesting() {
-  g_disable_initial_delay = true;
-}
-
 void WindowCycleList::OnWindowDestroying(WmWindow* window) {
   window->RemoveObserver(this);
 
@@ -531,7 +501,9 @@
 }
 
 bool WindowCycleList::ShouldShowUi() {
-  return windows_.size() > 1;
+  return windows_.size() > 1 &&
+         base::CommandLine::ForCurrentProcess()->HasSwitch(
+             switches::kAshEnableWindowCycleUi);
 }
 
 void WindowCycleList::InitWindowCycleView() {
diff --git a/ash/common/wm/window_cycle_list.h b/ash/common/wm/window_cycle_list.h
index 6d073d16..34af309 100644
--- a/ash/common/wm/window_cycle_list.h
+++ b/ash/common/wm/window_cycle_list.h
@@ -42,9 +42,6 @@
 
  private:
   friend class WindowCycleControllerTest;
-
-  static void DisableInitialDelayForTesting();
-
   const WindowList& windows() const { return windows_; }
 
   // WmWindowObserver overrides:
@@ -70,8 +67,6 @@
   int current_index_;
 
   // Wrapper for the window brought to the front.
-  // TODO(estade): remove ScopedShowWindow when we know we are happy launching
-  // the |cycle_view_| version.
   std::unique_ptr<ScopedShowWindow> showing_window_;
 
   // The top level View for the window cycle UI. May be null if the UI is not
diff --git a/ash/wm/window_cycle_controller_unittest.cc b/ash/wm/window_cycle_controller_unittest.cc
index 48ab3b3..ad61331f 100644
--- a/ash/wm/window_cycle_controller_unittest.cc
+++ b/ash/wm/window_cycle_controller_unittest.cc
@@ -78,8 +78,6 @@
     test::AshTestBase::SetUp();
     ASSERT_TRUE(test::TestShelfDelegate::instance());
 
-    WindowCycleList::DisableInitialDelayForTesting();
-
     shelf_view_test_.reset(new test::ShelfViewTestAPI(
         test::ShelfTestAPI(Shelf::ForPrimaryDisplay()).shelf_view()));
     shelf_view_test_->SetAnimationDuration(1);
@@ -175,12 +173,15 @@
   // all the windows and wrap around.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   EXPECT_TRUE(controller->IsCycling());
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
 
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   EXPECT_TRUE(controller->IsCycling());
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
 
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   EXPECT_TRUE(controller->IsCycling());
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 
   controller->StopCycling();
   EXPECT_FALSE(controller->IsCycling());
@@ -191,29 +192,29 @@
   wm::ActivateWindow(window1.get());
   wm::ActivateWindow(window0.get());
 
-  // Likewise we can cycle backwards through the windows.
+  // Likewise we can cycle backwards through all the windows.
   controller->HandleCycleWindow(WindowCycleController::BACKWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
   controller->HandleCycleWindow(WindowCycleController::BACKWARD);
-  controller->StopCycling();
   EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
-
-  // Reset our stacking order.
-  wm::ActivateWindow(window2.get());
-  wm::ActivateWindow(window1.get());
-  wm::ActivateWindow(window0.get());
+  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+  controller->StopCycling();
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 
   // When the screen is locked, cycling window does not take effect.
   WmShell::Get()->GetSessionStateDelegate()->LockScreen();
   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_FALSE(controller->IsCycling());
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+  controller->HandleCycleWindow(WindowCycleController::BACKWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 
-  // Unlock, it works again.
   WmShell::Get()->GetSessionStateDelegate()->UnlockScreen();
   EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  controller->StopCycling();
   EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
 
   // When a modal window is active, cycling window does not take effect.
@@ -226,13 +227,11 @@
   EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
-  EXPECT_FALSE(controller->IsCycling());
   EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
   controller->HandleCycleWindow(WindowCycleController::BACKWARD);
   EXPECT_TRUE(wm::IsActiveWindow(modal_window.get()));
-  EXPECT_FALSE(controller->IsCycling());
   EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
   EXPECT_FALSE(wm::IsActiveWindow(window2.get()));
@@ -251,13 +250,10 @@
   // Rotate focus, this should move focus to window0.
   WindowCycleController* controller = WmShell::Get()->window_cycle_controller();
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  controller->StopCycling();
   EXPECT_TRUE(wm::GetWindowState(window0.get())->IsActive());
-  EXPECT_FALSE(window1_state->IsActive());
 
   // One more time.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  controller->StopCycling();
   EXPECT_TRUE(window1_state->IsActive());
 }
 
@@ -276,14 +272,11 @@
   // Rotate focus, this should move focus to window1 and unminimize it.
   WindowCycleController* controller = WmShell::Get()->window_cycle_controller();
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  controller->StopCycling();
-  EXPECT_FALSE(window0_state->IsActive());
   EXPECT_FALSE(window1_state->IsMinimized());
   EXPECT_TRUE(window1_state->IsActive());
 
   // One more time back to w0.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  controller->StopCycling();
   EXPECT_TRUE(window0_state->IsActive());
 }
 
@@ -309,6 +302,23 @@
   EXPECT_EQ(window0.get(), GetWindows(controller)[0]);
   EXPECT_EQ(window2.get(), GetWindows(controller)[1]);
   EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
+
+  controller->StopCycling();
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+
+  controller->StopCycling();
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 }
 
 TEST_F(WindowCycleControllerTest, AlwaysOnTopMultiWindow) {
@@ -335,6 +345,26 @@
   EXPECT_EQ(window3.get(), GetWindows(controller)[1]);
   EXPECT_EQ(window2.get(), GetWindows(controller)[2]);
   EXPECT_EQ(window1.get(), GetWindows(controller)[3]);
+
+  controller->StopCycling();
+  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+
+  controller->StopCycling();
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 }
 
 TEST_F(WindowCycleControllerTest, AlwaysOnTopMultipleRootWindows) {
@@ -385,6 +415,26 @@
   EXPECT_EQ(window3.get(), GetWindows(controller)[1]);
   EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
   EXPECT_EQ(window0.get(), GetWindows(controller)[3]);
+
+  controller->StopCycling();
+  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  controller->StopCycling();
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window3.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
 }
 
 TEST_F(WindowCycleControllerTest, MostRecentlyUsed) {
@@ -408,19 +458,23 @@
   EXPECT_EQ(window2.get(), GetWindows(controller)[1]);
   EXPECT_EQ(window1.get(), GetWindows(controller)[2]);
 
-  // Cycling through then stopping the cycling will activate a window.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   controller->StopCycling();
   EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
 
-  // Cycling alone (without StopCycling()) doesn't activate.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
-
-  // Showing the Alt+Tab UI does however deactivate the erstwhile active window.
-  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 
   controller->StopCycling();
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window2.get()));
+
+  controller->HandleCycleWindow(WindowCycleController::FORWARD);
+  EXPECT_TRUE(wm::IsActiveWindow(window0.get()));
 }
 
 // Tests that beginning window selection hides the app list.
@@ -433,14 +487,10 @@
   EXPECT_TRUE(WmShell::Get()->GetAppListTargetVisibility());
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
   EXPECT_FALSE(WmShell::Get()->GetAppListTargetVisibility());
-
-  // Make sure that dismissing the app list this way doesn't pass activation
-  // to a different window.
-  EXPECT_FALSE(wm::IsActiveWindow(window0.get()));
-  EXPECT_FALSE(wm::IsActiveWindow(window1.get()));
 }
 
-// Tests that cycling through windows doesn't change their minimized state.
+// Tests that cycling through windows shows and minimizes windows as they
+// are passed.
 TEST_F(WindowCycleControllerTest, CyclePreservesMinimization) {
   WindowCycleController* controller = WmShell::Get()->window_cycle_controller();
 
@@ -453,7 +503,7 @@
 
   // On window 2.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
-  EXPECT_TRUE(IsWindowMinimized(window1.get()));
+  EXPECT_FALSE(IsWindowMinimized(window1.get()));
 
   // Back on window 1.
   controller->HandleCycleWindow(WindowCycleController::FORWARD);
diff --git a/ash/wm/window_mirror_view.cc b/ash/wm/window_mirror_view.cc
index 374207c..58c89e1 100644
--- a/ash/wm/window_mirror_view.cc
+++ b/ash/wm/window_mirror_view.cc
@@ -104,9 +104,6 @@
 }
 
 gfx::Rect WindowMirrorView::GetClientAreaBounds() const {
-  // The target window may not have a widget in unit tests.
-  if (!target_->GetInternalWidget())
-    return gfx::Rect();
   views::View* client_view = target_->GetInternalWidget()->client_view();
   return client_view->ConvertRectToWidget(client_view->GetLocalBounds());
 }
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 1173e9a..3f5251ce 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -6021,6 +6021,12 @@
         <message name="IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_DESCRIPTION" desc="Description for the flag to enable unified desktop mode.">
           Enable unified desktop mode which allows a window to span multiple displays.
         </message>
+        <message name="IDS_FLAGS_ASH_ENABLE_WINDOW_CYCLE_UI_NAME" desc="Name for the flag to enable the window cycle (Alt+Tab) UI.">
+          Enable window cycle UI.
+        </message>
+        <message name="IDS_FLAGS_ASH_ENABLE_WINDOW_CYCLE_UI_DESCRIPTION" desc="Description for the flag to enable the window cycle (Alt+Tab) UI.">
+          Enable window cycle UI (visual feedback for Alt+Tab).
+        </message>
         <message name="IDS_FLAGS_BOOT_ANIMATION" desc="Name for the flag for wallpaper boot animation (except for OOBE).">
           Boot animation
         </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index 5a01c86..509cdbf 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -911,6 +911,9 @@
     {"ash-enable-unified-desktop", IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_NAME,
      IDS_FLAGS_ASH_ENABLE_UNIFIED_DESKTOP_DESCRIPTION, kOsCrOS,
      SINGLE_VALUE_TYPE(ash::switches::kAshEnableUnifiedDesktop)},
+    {"ash-enable-window-cycle-ui", IDS_FLAGS_ASH_ENABLE_WINDOW_CYCLE_UI_NAME,
+     IDS_FLAGS_ASH_ENABLE_WINDOW_CYCLE_UI_DESCRIPTION, kOsCrOS,
+     SINGLE_VALUE_TYPE(ash::switches::kAshEnableWindowCycleUi)},
     {"enable-easy-unlock-proximity-detection",
      IDS_FLAGS_EASY_UNLOCK_PROXIMITY_DETECTION_NAME,
      IDS_FLAGS_EASY_UNLOCK_PROXIMITY_DETECTION_DESCRIPTION, kOsCrOS,
diff --git a/chrome/browser/browser_process_impl.cc b/chrome/browser/browser_process_impl.cc
index 1672f19..8709696 100644
--- a/chrome/browser/browser_process_impl.cc
+++ b/chrome/browser/browser_process_impl.cc
@@ -892,7 +892,8 @@
     scoped_refptr<update_client::Configurator> configurator =
         component_updater::MakeChromeComponentUpdaterConfigurator(
             base::CommandLine::ForCurrentProcess(),
-            io_thread()->system_url_request_context_getter());
+            io_thread()->system_url_request_context_getter(),
+            g_browser_process->local_state());
     // Creating the component updater does not do anything, components
     // need to be registered and Start() needs to be called.
     component_updater_.reset(component_updater::ComponentUpdateServiceFactory(
@@ -952,8 +953,7 @@
     Unpin();
 }
 
-void BrowserProcessImpl::OnKeepAliveRestartStateChanged(bool can_restart){
-}
+void BrowserProcessImpl::OnKeepAliveRestartStateChanged(bool can_restart) {}
 
 void BrowserProcessImpl::CreateWatchdogThread() {
   DCHECK(!created_watchdog_thread_ && !watchdog_thread_);
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 4514bc6f..67f4273 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -196,6 +196,11 @@
         TestParameter(NOT_IN_GUEST_MODE, "deleteOneItemFromToolbar")));
 
 WRAPPED_INSTANTIATE_TEST_CASE_P(
+    QuickView,
+    FileManagerBrowserTest,
+    ::testing::Values(TestParameter(NOT_IN_GUEST_MODE, "openQuickView")));
+
+WRAPPED_INSTANTIATE_TEST_CASE_P(
     DetailsPanel,
     FileManagerDetailsPanelBrowserTest,
     ::testing::Values(
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.cc b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
index fb5832cf..4e1b1ad 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.cc
@@ -32,7 +32,8 @@
 class ChromeConfigurator : public update_client::Configurator {
  public:
   ChromeConfigurator(const base::CommandLine* cmdline,
-                     net::URLRequestContextGetter* url_request_getter);
+                     net::URLRequestContextGetter* url_request_getter,
+                     PrefService* pref_service);
 
   // update_client::Configurator overrides.
   int InitialDelay() const override;
@@ -65,6 +66,8 @@
 
   ConfiguratorImpl configurator_impl_;
 
+  PrefService* pref_service_;  // This member is not owned by this class.
+
   ~ChromeConfigurator() override {}
 };
 
@@ -73,8 +76,12 @@
 // a custom message signing protocol and it does not depend on using HTTPS.
 ChromeConfigurator::ChromeConfigurator(
     const base::CommandLine* cmdline,
-    net::URLRequestContextGetter* url_request_getter)
-    : configurator_impl_(cmdline, url_request_getter, false) {}
+    net::URLRequestContextGetter* url_request_getter,
+    PrefService* pref_service)
+    : configurator_impl_(cmdline, url_request_getter, false),
+      pref_service_(pref_service) {
+  DCHECK(pref_service_);
+}
 
 int ChromeConfigurator::InitialDelay() const {
   return configurator_impl_.InitialDelay();
@@ -181,7 +188,8 @@
 }
 
 PrefService* ChromeConfigurator::GetPrefService() const {
-  return g_browser_process->local_state();
+  DCHECK(pref_service_);
+  return pref_service_;
 }
 
 }  // namespace
@@ -189,8 +197,9 @@
 scoped_refptr<update_client::Configurator>
 MakeChromeComponentUpdaterConfigurator(
     const base::CommandLine* cmdline,
-    net::URLRequestContextGetter* context_getter) {
-  return new ChromeConfigurator(cmdline, context_getter);
+    net::URLRequestContextGetter* context_getter,
+    PrefService* pref_service) {
+  return new ChromeConfigurator(cmdline, context_getter, pref_service);
 }
 
 }  // namespace component_updater
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator.h b/chrome/browser/component_updater/chrome_component_updater_configurator.h
index 1e777b2..674059c 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator.h
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator.h
@@ -8,6 +8,8 @@
 #include "base/memory/ref_counted.h"
 #include "components/update_client/configurator.h"
 
+class PrefService;
+
 namespace base {
 class CommandLine;
 }
@@ -21,7 +23,8 @@
 scoped_refptr<update_client::Configurator>
 MakeChromeComponentUpdaterConfigurator(
     const base::CommandLine* cmdline,
-    net::URLRequestContextGetter* context_getter);
+    net::URLRequestContextGetter* context_getter,
+    PrefService* pref_service);
 
 }  // namespace component_updater
 
diff --git a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
index b464a779..49ffa83 100644
--- a/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
+++ b/chrome/browser/component_updater/chrome_component_updater_configurator_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -11,27 +12,47 @@
 #include "components/component_updater/component_updater_switches.h"
 #include "components/component_updater/component_updater_url_constants.h"
 #include "components/component_updater/configurator_impl.h"
+#include "components/prefs/testing_pref_service.h"
 #include "components/update_client/configurator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
 namespace component_updater {
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestDisablePings) {
+class ChromeComponentUpdaterConfiguratorTest : public testing::Test {
+ public:
+  ChromeComponentUpdaterConfiguratorTest();
+  ~ChromeComponentUpdaterConfiguratorTest() override{};
+
+ protected:
+  PrefService* pref_service() { return pref_service_.get(); }
+
+ private:
+  std::unique_ptr<TestingPrefServiceSimple> pref_service_;
+
+  DISALLOW_COPY_AND_ASSIGN(ChromeComponentUpdaterConfiguratorTest);
+};
+
+ChromeComponentUpdaterConfiguratorTest::ChromeComponentUpdaterConfiguratorTest()
+    : pref_service_(new TestingPrefServiceSimple()) {}
+
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestDisablePings) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
   cmdline.AppendSwitchASCII(switches::kComponentUpdater, "disable-pings");
 
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
 
   const std::vector<GURL> pingUrls = config->PingUrl();
   EXPECT_TRUE(pingUrls.empty());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestFastUpdate) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestFastUpdate) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
   cmdline.AppendSwitchASCII(switches::kComponentUpdater, "fast-update");
 
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
 
   CHECK_EQ(10, config->InitialDelay());
   CHECK_EQ(6 * 60 * 60, config->NextCheckDelay());
@@ -40,7 +61,7 @@
   CHECK_EQ(10, config->UpdateDelay());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestOverrideUrl) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestOverrideUrl) {
   const char overrideUrl[] = "http://0.0.0.0/";
 
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
@@ -50,7 +71,8 @@
   val.append(overrideUrl);
   cmdline.AppendSwitchASCII(switches::kComponentUpdater, val.c_str());
 
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
 
   const std::vector<GURL> urls = config->UpdateUrl();
 
@@ -58,18 +80,20 @@
   ASSERT_EQ(overrideUrl, urls.at(0).possibly_invalid_spec());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestSwitchRequestParam) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestSwitchRequestParam) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
   cmdline.AppendSwitchASCII(switches::kComponentUpdater, "test-request");
 
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
 
   EXPECT_FALSE(config->ExtraRequestParams().empty());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestUpdaterDefaultUrl) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestUpdaterDefaultUrl) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
   const auto urls = config->UpdateUrl();
 
   // Expect the default url to be cryptographically secure.
@@ -77,16 +101,18 @@
   EXPECT_TRUE(urls.front().SchemeIsCryptographic());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestEnabledCupSigning) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestEnabledCupSigning) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
 
   EXPECT_TRUE(config->EnabledCupSigning());
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestUseEncryption) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestUseEncryption) {
   base::CommandLine* cmdline = base::CommandLine::ForCurrentProcess();
-  const auto config(MakeChromeComponentUpdaterConfigurator(cmdline, nullptr));
+  const auto config(
+      MakeChromeComponentUpdaterConfigurator(cmdline, nullptr, pref_service()));
 
   const auto urls = config->UpdateUrl();
   ASSERT_EQ(2u, urls.size());
@@ -115,9 +141,10 @@
   }
 }
 
-TEST(ChromeComponentUpdaterConfiguratorTest, TestEnabledComponentUpdates) {
+TEST_F(ChromeComponentUpdaterConfiguratorTest, TestEnabledComponentUpdates) {
   base::CommandLine cmdline(*base::CommandLine::ForCurrentProcess());
-  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr));
+  const auto config(MakeChromeComponentUpdaterConfigurator(&cmdline, nullptr,
+                                                           pref_service()));
   EXPECT_TRUE(config->EnabledComponentUpdates());
 }
 
diff --git a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
index ccee531..5a3976cb 100644
--- a/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
+++ b/chrome/browser/ui/webui/options/chromeos/storage_manager_handler.cc
@@ -151,19 +151,19 @@
   web_ui()->RegisterMessageCallback(
       "updateStorageInfo",
       base::Bind(&StorageManagerHandler::HandleUpdateStorageInfo,
-                 base::Unretained(this)));
+                 weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
       "openDownloads",
       base::Bind(&StorageManagerHandler::HandleOpenDownloads,
-                 base::Unretained(this)));
+                 weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
       "openArcStorage",
       base::Bind(&StorageManagerHandler::HandleOpenArcStorage,
-                 base::Unretained(this)));
+                 weak_ptr_factory_.GetWeakPtr()));
   web_ui()->RegisterMessageCallback(
       "clearDriveCache",
       base::Bind(&StorageManagerHandler::HandleClearDriveCache,
-                 base::Unretained(this)));
+                 weak_ptr_factory_.GetWeakPtr()));
 }
 
 void StorageManagerHandler::HandleUpdateStorageInfo(
@@ -422,7 +422,7 @@
       "options.StorageManager.showArcItem");
   bool success = arc::ArcStorageManager::Get()->GetApplicationsSize(
       base::Bind(&StorageManagerHandler::OnGetArcSize,
-                 base::Unretained(this)));
+                 weak_ptr_factory_.GetWeakPtr()));
   if (!success)
     updating_arc_size_ = false;
 }
diff --git a/chromeos/CHROMEOS_LKGM b/chromeos/CHROMEOS_LKGM
index 7e9b339..c03a0f0 100644
--- a/chromeos/CHROMEOS_LKGM
+++ b/chromeos/CHROMEOS_LKGM
@@ -1 +1 @@
-8703.0.0
\ No newline at end of file
+8705.0.0
\ No newline at end of file
diff --git a/content/renderer/media/webrtc_audio_device_not_impl.cc b/content/renderer/media/webrtc_audio_device_not_impl.cc
index a86fca0..016c32e 100644
--- a/content/renderer/media/webrtc_audio_device_not_impl.cc
+++ b/content/renderer/media/webrtc_audio_device_not_impl.cc
@@ -270,4 +270,32 @@
   return 0;
 }
 
+bool WebRtcAudioDeviceNotImpl::BuiltInAGCIsAvailable() const {
+  return false;
+}
+
+int32_t WebRtcAudioDeviceNotImpl::EnableBuiltInAGC(bool enable) {
+  return 0;
+}
+
+bool WebRtcAudioDeviceNotImpl::BuiltInNSIsAvailable() const {
+  return false;
+}
+
+int32_t WebRtcAudioDeviceNotImpl::EnableBuiltInNS(bool enable) {
+  return 0;
+}
+
+#if defined(OS_IOS)
+int WebRtcAudioDeviceNotImpl::GetPlayoutAudioParameters(
+    AudioParameters* params) const {
+  return 0;
+}
+
+int WebRtcAudioDeviceNotImpl::GetRecordAudioParameters(
+    AudioParameters* params) const {
+  return 0;
+}
+#endif  // OS_IOS
+
 }  // namespace content
diff --git a/content/renderer/media/webrtc_audio_device_not_impl.h b/content/renderer/media/webrtc_audio_device_not_impl.h
index f0291ed9..e9a98f0 100644
--- a/content/renderer/media/webrtc_audio_device_not_impl.h
+++ b/content/renderer/media/webrtc_audio_device_not_impl.h
@@ -103,7 +103,15 @@
   int32_t SetAGC(bool enable) override;
   bool AGC() const override;
   bool BuiltInAECIsAvailable() const override;
+  bool BuiltInAGCIsAvailable() const override;
+  bool BuiltInNSIsAvailable() const override;
   int32_t EnableBuiltInAEC(bool enable) override;
+  int32_t EnableBuiltInAGC(bool enable) override;
+  int32_t EnableBuiltInNS(bool enable) override;
+#if defined(OS_IOS)
+  int GetPlayoutAudioParameters(AudioParameters* params) const override;
+  int GetRecordAudioParameters(AudioParameters* params) const override;
+#endif  // OS_IOS
 
  protected:
   ~WebRtcAudioDeviceNotImpl() override{};
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 96c5f18..ede53df 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -135,7 +135,7 @@
 
 crbug.com/636222 [ Mac10.10 ] fast/repaint/fixed-and-absolute-position-scrolled.html [ Failure ]
 
-crbug.com/636271 [ Mac10.10 ] fast/repaint/resize-iframe-text.html [ Pass Failure ]
+crbug.com/636271 [ Mac ] fast/repaint/resize-iframe-text.html [ Pass Failure ]
 crbug.com/636271 [ Linux ] fast/repaint/resize-iframe-text.html [ Pass Failure ]
 crbug.com/636271 [ Win ] fast/repaint/resize-iframe-text.html [ Pass Failure ]
 
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/parsing.html b/third_party/WebKit/LayoutTests/custom-elements/spec/parsing.html
new file mode 100644
index 0000000..e6b38428
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/parsing.html
@@ -0,0 +1,285 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/custom-elements-helpers.js"></script>
+<body>
+<script>
+'use strict';
+
+// Looks up the preceeding element (which should be a template
+// element) and creates a Promise test. The test name is taken from
+// the template's data-test attribute.
+//
+// The content of the template is loaded into an iframe. On load, f
+// is passed the frame's content window to run assertions.
+function test_with_content(f) {
+  let t = document.currentScript.previousElementSibling;
+  test_with_window(f, t.dataset.test, t.innerHTML);
+}
+
+// Searches the document for an iframe with the specified content window.
+function findFrameWithWindow(w) {
+  return Array.prototype.find.call(document.querySelectorAll('iframe'), (f) => {
+    return f.contentWindow === w;
+  });
+}
+
+test_with_window((w) => {
+  assert_equals(findFrameWithWindow(w).contentWindow, w,
+                'should find the frame with this window');
+  assert_equals(findFrameWithWindow(window), undefined,
+                'should return undefined if there is no such frame');
+}, 'sanity check the findFrameWithWindow function');
+</script>
+
+<template data-test="the parser synchronously creates elements">
+  <script>
+  'use strict';
+
+  window.invocations = [];
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      invocations.push('constructor');
+    }
+    static get observedAttributes() { return ['x']; }
+    attributeChangedCallback(name, oldValue, newValue, nsuri) {
+      invocations.push(`${name}="${newValue}"`);
+    }
+    connectedCallback() {
+      invocations.push('connected');
+    }
+  });
+  </script>
+  <a-a x="y">
+    <script>
+    'use strict';
+
+    invocations.push('script');
+    </script>
+  </a-a>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  assert_array_equals(w.invocations,
+                      ['constructor', 'x="y"', 'connected', 'script']);
+});
+</script>
+
+<template data-test="element creation failure produces unknown element">
+  <script>
+  'use strict';
+
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+
+      // Returning this different, in-use element causes element
+      // creation to fail in
+      // https://dom.spec.whatwg.org/#concept-create-element steps
+      // 6.4-9, eg: "If result has children then then throw a
+      // NotSupportedError."
+      return document.documentElement;
+    }
+  });
+  </script>
+  <a-a>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  let e = w.document.querySelector('a-a');
+  assert_true(e.matches(':not(:defined)'));
+  assert_equals(Object.getPrototypeOf(e), w.HTMLUnknownElement.prototype);
+});
+</script>
+
+<template data-test="modify tree during creation">
+  <script>
+  'use strict';
+
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      document.querySelector('b').remove();
+    }
+  });
+  </script>
+  <b>
+    <a-a>
+  </b>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  assert_equals(w.document.querySelectorAll('b').length, 0);
+});
+</script>
+
+<template data-test="destructive writes are blocked during construction">
+  <script>
+  // Custom element constructors do not set the insertion point, which
+  // makes document.write() "destructive." However they increment the
+  // ignore-destructive-writes counter, which blocks document.write.
+  // https://html.spec.whatwg.org/#create-an-element-for-the-token
+  // https://github.com/whatwg/html/issues/1630
+  // https://html.spec.whatwg.org/#document.write()
+  'use strict';
+
+  window.invocations = [];
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      invocations.push('constructor');
+      document.write(
+          `<script>'use strict'; invocations.push('written');</scr${'i'}pt>`);
+    }
+    connectedCallback() {
+      invocations.push('connected');
+    }
+  });
+  </script>
+  <a-a>
+  <script>
+  'use strict';
+  invocations.push('parsed');
+  </script>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  assert_array_equals(
+      w.invocations,
+      ['constructor', 'connected', 'parsed'],
+      'the destructive document.write content should have been ignored');
+});
+</script>
+
+<template data-test="non-destructive writes are not blocked">
+  <script>
+  // Script running sets the insertion point, which makes makes
+  // document.write() "non-destructive." Custom elements do not block
+  // non-destructive writes.
+  // https://html.spec.whatwg.org/#create-an-element-for-the-token
+  // https://html.spec.whatwg.org/#document.write()
+  'use strict';
+
+  window.invocations = [];
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      invocations.push('constructor');
+      document.write(
+          `<script>'use strict'; invocations.push('written');</scr${'i'}pt>`);
+    }
+    connectedCallback() {
+      invocations.push('connected');
+    }
+  });
+  document.write('<a-a>');
+  invocations.push('post write');
+  </script>
+  <script>
+  'use strict';
+  invocations.push('parsed');
+  </script>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  assert_array_equals(
+      w.invocations,
+      ['constructor', 'connected', 'post write', 'written', 'parsed'],
+      'the non-destructive document.write content should have been inserted');
+});
+</script>
+
+<template data-test="innerHTML is not blocked by custom element constructors">
+  <script>
+  'use strict';
+
+  window.invocations = [];
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      invocations.push(`construct ${this.id}`);
+      if (!this.id) {
+        // If the ID attribute is not set, this was created
+        // synchronously by the parser. Adding children at this point
+        // would cause creation to fail, so embiggen the previous
+        // element instead.
+        document.querySelector('span').innerHTML = `<a-a id="r">`;
+      }
+    }
+    connectedCallback() {
+      invocations.push(`connected ${this.parentNode.localName}/${this.id}`);
+    }
+  });
+  </script>
+  <span></span>
+  <a-a id="q"></a-a>
+  <script>
+  'use strict';
+  invocations.push('parsed');
+  </script>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  assert_array_equals(
+      w.invocations,
+      ['construct ', 'construct r', 'connected span/r', 'connected body/q',
+       'parsed'],
+      'custom element constructors should not block innerHTML');
+});
+</script>
+
+
+<template data-test="parsing without a browsing context should not create custom elements">
+  <body>
+  <script>
+  'use strict';
+
+  let f = parent.findFrameWithWindow(window);
+  f.invocations = [];
+
+  customElements.define('a-a', class extends HTMLElement {
+    constructor() {
+      super();
+      f.invocations.push(this);
+    }
+  });
+  </script>
+  <a-a></a-a>
+  <script>
+  f.detached = document.implementation.createHTMLDocument();
+  f.detached.documentElement.appendChild(document.body);
+  </script>
+  <a-a></a-a>
+</template>
+<script>
+'use strict';
+
+test_with_content((w) => {
+  let f = findFrameWithWindow(w);
+  assert_array_equals(f.invocations,
+                      [f.detached.querySelector('a-a:first-of-type')],
+                      'one element should have been constructed');
+  assert_true(f.invocations[0].matches(':defined'),
+              'the element should have been created successfully');
+
+  let elements = f.detached.querySelectorAll('a-a');
+  console.log(f.invocations[0].parentNode);
+  assert_equals(elements.length, 2,
+                'two elements should have been created');
+  assert_equals(Object.getPrototypeOf(elements[1]), w.HTMLElement.prototype,
+                'the second element should be un-upgraded, not failed');
+});
+</script>
diff --git a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
index 7a1c7196..114e1b00 100644
--- a/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
+++ b/third_party/WebKit/LayoutTests/custom-elements/spec/resources/custom-elements-helpers.js
@@ -4,7 +4,7 @@
     f.srcdoc = srcdoc ? srcdoc : '';
     f.onload = (event) => {
       let w = f.contentWindow;
-      t.add_cleanup(() => f.remove());
+      t.add_cleanup(() => f.parentNode && f.remove());
       resolve(w);
     };
     document.body.appendChild(f);
diff --git a/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html b/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html
index 9cffe1b..a5c4137 100644
--- a/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html
+++ b/third_party/WebKit/LayoutTests/fast/css/invalidation/nth-pseudo.html
@@ -56,6 +56,6 @@
         t3.insertBefore(document.createElement("div"), t3.firstChild);
         assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 2);
         backgroundIsGreen(second);
-    }, "Prepending an element sibling should not affect :nth-last-child of succeeding siblings.");
+    }, "Prepending an element sibling causing :nth-child class invalidation.");
 
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets-expected.txt b/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets-expected.txt
index fff2248d..7396617 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets-expected.txt
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets-expected.txt
@@ -5,6 +5,7 @@
 
 PASS getComputedStyle(root.querySelector('div')).color is "rgb(0, 128, 0)"
 PASS getComputedStyle(alternate).color is "rgb(0, 128, 0)"
+PASS host.shadowRoot.styleSheets[0].title is null
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets.html b/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets.html
index 1b97b2c..c18b603 100644
--- a/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets.html
+++ b/third_party/WebKit/LayoutTests/fast/dom/shadow/alternate-stylesheets.html
@@ -14,4 +14,5 @@
 
     shouldBeEqualToString("getComputedStyle(root.querySelector('div')).color", "rgb(0, 128, 0)");
     shouldBeEqualToString("getComputedStyle(alternate).color", "rgb(0, 128, 0)");
+    shouldBeNull("host.shadowRoot.styleSheets[0].title");
 </script>
diff --git a/third_party/WebKit/LayoutTests/fast/parser/frameset-in-fragment.html b/third_party/WebKit/LayoutTests/fast/parser/frameset-in-fragment.html
new file mode 100644
index 0000000..4b01c6e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/parser/frameset-in-fragment.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script>
+document.getElementsByTagName('html')[0].insertAdjacentHTML('afterbegin', '<p><frameset></frameset></p>');
+test(() => {}, "Forced body tag insertion in a fragment shouldn't crash on frameset");
+</script>
diff --git a/third_party/WebKit/LayoutTests/shadow-dom/link-title.html b/third_party/WebKit/LayoutTests/shadow-dom/link-title.html
index 1e191c3..94566b4c 100644
--- a/third_party/WebKit/LayoutTests/shadow-dom/link-title.html
+++ b/third_party/WebKit/LayoutTests/shadow-dom/link-title.html
@@ -41,4 +41,11 @@
   assert_equals(colorFor(host.shadowRoot.querySelector('#shadowChild4')), 'rgb(0, 0, 0)');
 }, '<link rel="alternate stylesheet" title="xxx"> shoule behave as <link rel="alternate stylesheet"> (never enabled because title is ignored) in a connected shadow tree.');
 
+test(() => {
+  assert_equals(host.shadowRoot.styleSheets.length, 4);
+  assert_equals(host.shadowRoot.styleSheets[0].title, null);
+  assert_equals(host.shadowRoot.styleSheets[1].title, null);
+  assert_equals(host.shadowRoot.styleSheets[2].title, null);
+  assert_equals(host.shadowRoot.styleSheets[3].title, null);
+}, 'StyleSheet.title should always be null in shadow trees.');
 </script>
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
index a4083d93..01172cd 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimations.cpp
@@ -432,15 +432,15 @@
     std::unique_ptr<CompositorFilterOperations> ops = CompositorFilterOperations::create();
     toCompositorFilterOperations(toAnimatableFilterOperations(value)->operations(), ops.get());
 
-    CompositorFilterKeyframe filterKeyframe(keyframe->offset(), std::move(ops));
-    curve.addKeyframe(filterKeyframe, keyframeTimingFunction);
+    CompositorFilterKeyframe filterKeyframe(keyframe->offset(), *ops, keyframeTimingFunction);
+    curve.addKeyframe(filterKeyframe);
 }
 
 void addKeyframeToCurve(CompositorFloatAnimationCurve& curve, Keyframe::PropertySpecificKeyframe* keyframe,
     const AnimatableValue* value, const TimingFunction& keyframeTimingFunction)
 {
-    CompositorFloatKeyframe floatKeyframe(keyframe->offset(), toAnimatableDouble(value)->toDouble());
-    curve.addKeyframe(floatKeyframe, keyframeTimingFunction);
+    CompositorFloatKeyframe floatKeyframe(keyframe->offset(), toAnimatableDouble(value)->toDouble(), keyframeTimingFunction);
+    curve.addKeyframe(floatKeyframe);
 }
 
 void addKeyframeToCurve(CompositorTransformAnimationCurve& curve, Keyframe::PropertySpecificKeyframe* keyframe,
@@ -449,8 +449,8 @@
     std::unique_ptr<CompositorTransformOperations> ops = CompositorTransformOperations::create();
     toCompositorTransformOperations(toAnimatableTransform(value)->transformOperations(), ops.get());
 
-    CompositorTransformKeyframe transformKeyframe(keyframe->offset(), std::move(ops));
-    curve.addKeyframe(transformKeyframe, keyframeTimingFunction);
+    CompositorTransformKeyframe transformKeyframe(keyframe->offset(), *ops, keyframeTimingFunction);
+    curve.addKeyframe(transformKeyframe);
 }
 
 template <typename PlatformAnimationCurveType>
diff --git a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
index f4eb231..6f18f9e 100644
--- a/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
+++ b/third_party/WebKit/Source/core/animation/CompositorAnimationsTest.cpp
@@ -259,6 +259,14 @@
     {
         return convertToCompositorAnimation(effect, 1.0);
     }
+
+    void ExpectKeyframeTimingFunctionCubic(const CompositorFloatKeyframe& keyframe, const CubicBezierTimingFunction::EaseType easeType)
+    {
+        auto keyframeTimingFunction = keyframe.getTimingFunctionForTesting();
+        DCHECK_EQ(keyframeTimingFunction->getType(), TimingFunction::Type::CUBIC_BEZIER);
+        const auto& cubicTimingFunction = toCubicBezierTimingFunction(*keyframeTimingFunction);
+        EXPECT_EQ(cubicTimingFunction.getEaseType(), easeType);
+    }
 };
 
 class LayoutObjectProxy : public LayoutObject {
@@ -649,16 +657,16 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 
-    EXPECT_EQ(0, keyframes[0].time);
-    EXPECT_EQ(2.0f, keyframes[0].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(0));
+    EXPECT_EQ(0, keyframes[0]->time());
+    EXPECT_EQ(2.0f, keyframes[0]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[0]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(1.0, keyframes[1].time);
-    EXPECT_EQ(5.0f, keyframes[1].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1));
+    EXPECT_EQ(1.0, keyframes[1]->time());
+    EXPECT_EQ(5.0f, keyframes[1]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[1]->getTimingFunctionForTesting()->getType());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationDuration)
@@ -674,10 +682,10 @@
     std::unique_ptr<CompositorAnimation> animation = convertToCompositorAnimation(*effect);
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 
-    EXPECT_EQ(duration, keyframes[1].time);
+    EXPECT_EQ(duration, keyframes[1]->time());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimationLinear)
@@ -702,24 +710,24 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(4UL, keyframes.size());
 
-    EXPECT_EQ(0, keyframes[0].time);
-    EXPECT_EQ(2.0f, keyframes[0].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(0));
+    EXPECT_EQ(0, keyframes[0]->time());
+    EXPECT_EQ(2.0f, keyframes[0]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[0]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(0.25, keyframes[1].time);
-    EXPECT_EQ(-1.0f, keyframes[1].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1));
+    EXPECT_EQ(0.25, keyframes[1]->time());
+    EXPECT_EQ(-1.0f, keyframes[1]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[1]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(0.5, keyframes[2].time);
-    EXPECT_EQ(20.0f, keyframes[2].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(2));
+    EXPECT_EQ(0.5, keyframes[2]->time());
+    EXPECT_EQ(20.0f, keyframes[2]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[2]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(1.0, keyframes[3].time);
-    EXPECT_EQ(5.0f, keyframes[3].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3));
+    EXPECT_EQ(1.0, keyframes[3]->time());
+    EXPECT_EQ(5.0f, keyframes[3]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[3]->getTimingFunctionForTesting()->getType());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createSimpleOpacityAnimationStartDelay)
@@ -743,11 +751,11 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 
-    EXPECT_EQ(1.75, keyframes[1].time);
-    EXPECT_EQ(5.0f, keyframes[1].value);
+    EXPECT_EQ(1.75, keyframes[1]->time());
+    EXPECT_EQ(5.0f, keyframes[1]->value());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createMultipleKeyframeOpacityAnimationChained)
@@ -777,24 +785,24 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(4UL, keyframes.size());
 
-    EXPECT_EQ(0, keyframes[0].time);
-    EXPECT_EQ(2.0f, keyframes[0].value);
-    EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE, keyframedFloatCurve->getKeyframeEaseTypeForTesting(0));
+    EXPECT_EQ(0, keyframes[0]->time());
+    EXPECT_EQ(2.0f, keyframes[0]->value());
+    ExpectKeyframeTimingFunctionCubic(*keyframes[0], CubicBezierTimingFunction::EaseType::EASE);
 
-    EXPECT_EQ(0.5, keyframes[1].time);
-    EXPECT_EQ(-1.0f, keyframes[1].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1));
+    EXPECT_EQ(0.5, keyframes[1]->time());
+    EXPECT_EQ(-1.0f, keyframes[1]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[1]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(1.0, keyframes[2].time);
-    EXPECT_EQ(20.0f, keyframes[2].value);
-    EXPECT_EQ(CubicBezierTimingFunction::EaseType::CUSTOM, keyframedFloatCurve->getKeyframeEaseTypeForTesting(2));
+    EXPECT_EQ(1.0, keyframes[2]->time());
+    EXPECT_EQ(20.0f, keyframes[2]->value());
+    ExpectKeyframeTimingFunctionCubic(*keyframes[2], CubicBezierTimingFunction::EaseType::CUSTOM);
 
-    EXPECT_EQ(2.0, keyframes[3].time);
-    EXPECT_EQ(5.0f, keyframes[3].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3));
+    EXPECT_EQ(2.0, keyframes[3]->time());
+    EXPECT_EQ(5.0f, keyframes[3]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[3]->getTimingFunctionForTesting()->getType());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimation)
@@ -825,26 +833,26 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(4UL, keyframes.size());
 
-    EXPECT_TRUE(keyframedFloatCurve->curveHasLinearTimingFunctionForTesting());
+    EXPECT_EQ(keyframedFloatCurve->getTimingFunctionForTesting()->getType(), TimingFunction::Type::LINEAR);
 
-    EXPECT_EQ(0, keyframes[0].time);
-    EXPECT_EQ(2.0f, keyframes[0].value);
-    EXPECT_EQ(CubicBezierTimingFunction::EaseType::EASE_IN, keyframedFloatCurve->getKeyframeEaseTypeForTesting(0));
+    EXPECT_EQ(0, keyframes[0]->time());
+    EXPECT_EQ(2.0f, keyframes[0]->value());
+    ExpectKeyframeTimingFunctionCubic(*keyframes[0], CubicBezierTimingFunction::EaseType::EASE_IN);
 
-    EXPECT_EQ(0.25, keyframes[1].time);
-    EXPECT_EQ(-1.0f, keyframes[1].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1));
+    EXPECT_EQ(0.25, keyframes[1]->time());
+    EXPECT_EQ(-1.0f, keyframes[1]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[1]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(0.5, keyframes[2].time);
-    EXPECT_EQ(20.0f, keyframes[2].value);
-    EXPECT_EQ(CubicBezierTimingFunction::EaseType::CUSTOM, keyframedFloatCurve->getKeyframeEaseTypeForTesting(2));
+    EXPECT_EQ(0.5, keyframes[2]->time());
+    EXPECT_EQ(20.0f, keyframes[2]->value());
+    ExpectKeyframeTimingFunctionCubic(*keyframes[2], CubicBezierTimingFunction::EaseType::CUSTOM);
 
-    EXPECT_EQ(1.0, keyframes[3].time);
-    EXPECT_EQ(5.0f, keyframes[3].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(3));
+    EXPECT_EQ(1.0, keyframes[3]->time());
+    EXPECT_EQ(5.0f, keyframes[3]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[3]->getTimingFunctionForTesting()->getType());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, createReversedOpacityAnimationNegativeStartDelay)
@@ -870,7 +878,7 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 }
 
@@ -895,7 +903,7 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 }
 
@@ -943,18 +951,25 @@
 
     std::unique_ptr<CompositorFloatAnimationCurve> keyframedFloatCurve = animation->floatCurveForTesting();
 
-    Vector<CompositorFloatKeyframe> keyframes = keyframedFloatCurve->keyframesForTesting();
+    auto curveTimingFunction = keyframedFloatCurve->getTimingFunctionForTesting();
+    EXPECT_EQ(curveTimingFunction->getType(), TimingFunction::Type::CUBIC_BEZIER);
+    const auto& cubicTimingFunction = toCubicBezierTimingFunction(*curveTimingFunction);
+    EXPECT_EQ(cubicTimingFunction.getEaseType(), CubicBezierTimingFunction::EaseType::CUSTOM);
+    EXPECT_EQ(cubicTimingFunction.x1(), 1.0);
+    EXPECT_EQ(cubicTimingFunction.y1(), 2.0);
+    EXPECT_EQ(cubicTimingFunction.x2(), 3.0);
+    EXPECT_EQ(cubicTimingFunction.y2(), 4.0);
+
+    CompositorFloatAnimationCurve::Keyframes keyframes = keyframedFloatCurve->keyframesForTesting();
     ASSERT_EQ(2UL, keyframes.size());
 
-    EXPECT_EQ(CubicBezierTimingFunction::EaseType::CUSTOM, keyframedFloatCurve->getCurveEaseTypeForTesting());
+    EXPECT_EQ(0, keyframes[0]->time());
+    EXPECT_EQ(2.0f, keyframes[0]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[0]->getTimingFunctionForTesting()->getType());
 
-    EXPECT_EQ(0, keyframes[0].time);
-    EXPECT_EQ(2.0f, keyframes[0].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(0));
-
-    EXPECT_EQ(1.0, keyframes[1].time);
-    EXPECT_EQ(5.0f, keyframes[1].value);
-    EXPECT_TRUE(keyframedFloatCurve->keyframeHasLinearTimingFunctionForTesting(1));
+    EXPECT_EQ(1.0, keyframes[1]->time());
+    EXPECT_EQ(5.0f, keyframes[1]->value());
+    EXPECT_EQ(TimingFunction::Type::LINEAR, keyframes[1]->getTimingFunctionForTesting()->getType());
 }
 
 TEST_F(AnimationCompositorAnimationsTest, cancelIncompatibleCompositorAnimations)
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi
index cb40f8f..2441698 100644
--- a/third_party/WebKit/Source/core/core.gypi
+++ b/third_party/WebKit/Source/core/core.gypi
@@ -3267,6 +3267,8 @@
             'html/parser/HTMLParserIdioms.cpp',
             'html/parser/HTMLParserOptions.cpp',
             'html/parser/HTMLParserOptions.h',
+            'html/parser/HTMLParserReentryPermit.cpp',
+            'html/parser/HTMLParserReentryPermit.h',
             'html/parser/HTMLParserScheduler.cpp',
             'html/parser/HTMLParserScheduler.h',
             'html/parser/HTMLParserThread.cpp',
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp
index 8ba679e..1236dcaa 100644
--- a/third_party/WebKit/Source/core/dom/Document.cpp
+++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -107,6 +107,7 @@
 #include "core/dom/VisitedLinkState.h"
 #include "core/dom/XMLDocument.h"
 #include "core/dom/custom/CustomElement.h"
+#include "core/dom/custom/CustomElementsRegistry.h"
 #include "core/dom/custom/V0CustomElementMicrotaskRunQueue.h"
 #include "core/dom/custom/V0CustomElementRegistrationContext.h"
 #include "core/dom/shadow/ElementShadow.h"
@@ -460,6 +461,12 @@
 
         m_fetcher = m_frame->loader().documentLoader()->fetcher();
         FrameFetchContext::provideDocumentToContext(m_fetcher->context(), this);
+
+        CustomElementsRegistry* registry = m_frame->localDOMWindow()
+            ? m_frame->localDOMWindow()->maybeCustomElements()
+            : nullptr;
+        if (registry && m_registrationContext)
+            registry->entangle(m_registrationContext);
     } else if (m_importsController) {
         m_fetcher = FrameFetchContext::createContextAndFetcher(nullptr, this);
     } else {
diff --git a/third_party/WebKit/Source/core/dom/StyleEngine.cpp b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
index 8807b83..8b7bd54 100644
--- a/third_party/WebKit/Source/core/dom/StyleEngine.cpp
+++ b/third_party/WebKit/Source/core/dom/StyleEngine.cpp
@@ -529,9 +529,10 @@
     }
 
     DCHECK(styleSheet);
-    styleSheet->setTitle(e->title());
-    if (!e->isInShadowTree())
+    if (!e->isInShadowTree()) {
+        styleSheet->setTitle(e->title());
         setPreferredStylesheetSetNameIfNotSet(e->title());
+    }
     return styleSheet;
 }
 
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp
index 1bd3aad..6ecc7a8e 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.cpp
@@ -20,6 +20,7 @@
 #include "core/dom/custom/CustomElementUpgradeReaction.h"
 #include "core/dom/custom/CustomElementUpgradeSorter.h"
 #include "core/dom/custom/V0CustomElementRegistrationContext.h"
+#include "core/frame/LocalDOMWindow.h"
 #include "wtf/Allocator.h"
 
 namespace blink {
@@ -63,16 +64,19 @@
 };
 
 CustomElementsRegistry* CustomElementsRegistry::create(
-    Document* document)
+    const LocalDOMWindow* owner)
 {
-    CustomElementsRegistry* registry = new CustomElementsRegistry(document);
-    if (V0CustomElementRegistrationContext* v0Context = registry->v0())
-        v0Context->setV1(registry);
+    CustomElementsRegistry* registry = new CustomElementsRegistry(owner);
+    Document* document = owner->document();
+    if (V0CustomElementRegistrationContext* v0 =
+        document ? document->registrationContext() : nullptr)
+        registry->entangle(v0);
     return registry;
 }
 
-CustomElementsRegistry::CustomElementsRegistry(Document* document)
-    : m_document(document)
+CustomElementsRegistry::CustomElementsRegistry(const LocalDOMWindow* owner)
+    : m_owner(owner)
+    , m_v0 (new V0RegistrySet())
     , m_upgradeCandidates(new UpgradeCandidateMap())
 {
 }
@@ -80,7 +84,8 @@
 DEFINE_TRACE(CustomElementsRegistry)
 {
     visitor->trace(m_definitions);
-    visitor->trace(m_document);
+    visitor->trace(m_owner);
+    visitor->trace(m_v0);
     visitor->trace(m_upgradeCandidates);
     visitor->trace(m_whenDefinedPromiseMap);
 }
@@ -189,20 +194,35 @@
     return definition->getConstructorForScript();
 }
 
+CustomElementDefinition* CustomElementsRegistry::definitionFor(const CustomElementDescriptor& desc) const
+{
+    CustomElementDefinition* definition = definitionForName(desc.name());
+    if (!definition)
+        return nullptr;
+    // The definition for a customized built-in element, such as
+    // <button is="my-button"> should not be provided for an
+    // autonomous element, such as <my-button>, even though the
+    // name "my-button" matches.
+    return definition->descriptor() == desc ? definition : nullptr;
+}
+
 bool CustomElementsRegistry::nameIsDefined(const AtomicString& name) const
 {
     return m_definitions.contains(name);
 }
 
-V0CustomElementRegistrationContext* CustomElementsRegistry::v0()
+void CustomElementsRegistry::entangle(V0CustomElementRegistrationContext* v0)
 {
-    return m_document->registrationContext();
+    m_v0->add(v0);
+    v0->setV1(this);
 }
 
 bool CustomElementsRegistry::v0NameIsDefined(const AtomicString& name)
 {
-    if (V0CustomElementRegistrationContext* v0Context = v0())
-        return v0Context->nameIsDefined(name);
+    for (const auto& v0 : *m_v0) {
+        if (v0->nameIsDefined(name))
+            return true;
+    }
     return false;
 }
 
@@ -264,7 +284,12 @@
     }
 
     m_upgradeCandidates->remove(it);
-    sorter.sorted(elements, m_document.get());
+
+    Document* document = m_owner->document();
+    if (!document)
+        return;
+
+    sorter.sorted(elements, document);
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.h b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.h
index e5b58b4a..ecb2074 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.h
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistry.h
@@ -20,10 +20,10 @@
 class CustomElementDefinition;
 class CustomElementDefinitionBuilder;
 class CustomElementDescriptor;
-class Document;
 class Element;
 class ElementRegistrationOptions;
 class ExceptionState;
+class LocalDOMWindow;
 class ScriptPromiseResolver;
 class ScriptState;
 class ScriptValue;
@@ -35,7 +35,7 @@
     DEFINE_WRAPPERTYPEINFO();
     WTF_MAKE_NONCOPYABLE(CustomElementsRegistry);
 public:
-    static CustomElementsRegistry* create(Document*);
+    static CustomElementsRegistry* create(const LocalDOMWindow*);
 
     virtual ~CustomElementsRegistry() = default;
 
@@ -56,6 +56,10 @@
     bool nameIsDefined(const AtomicString& name) const;
     CustomElementDefinition* definitionForName(const AtomicString& name) const;
 
+    // TODO(dominicc): Switch most callers of definitionForName to
+    // definitionFor when implementing type extensions.
+    CustomElementDefinition* definitionFor(const CustomElementDescriptor&) const;
+
     // TODO(dominicc): Consider broadening this API when type extensions are
     // implemented.
     void addCandidate(Element*);
@@ -64,14 +68,15 @@
         const AtomicString& name,
         ExceptionState&);
 
+    void entangle(V0CustomElementRegistrationContext*);
+
     DECLARE_TRACE();
 
 private:
-    friend class CustomElementsRegistryTestBase;
+    friend class CustomElementsRegistryTest;
 
-    CustomElementsRegistry(Document*);
+    CustomElementsRegistry(const LocalDOMWindow*);
 
-    V0CustomElementRegistrationContext* v0();
     bool v0NameIsDefined(const AtomicString& name);
 
     void collectCandidates(
@@ -85,7 +90,10 @@
         HeapHashMap<AtomicString, Member<CustomElementDefinition>>;
     DefinitionMap m_definitions;
 
-    Member<Document> m_document;
+    Member<const LocalDOMWindow> m_owner;
+
+    using V0RegistrySet = HeapHashSet<WeakMember<V0CustomElementRegistrationContext>>;
+    Member<V0RegistrySet> m_v0;
 
     using UpgradeCandidateSet = HeapHashSet<WeakMember<Element>>;
     using UpgradeCandidateMap = HeapHashMap<
diff --git a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
index 96321e1..9f8d84ae 100644
--- a/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
+++ b/third_party/WebKit/Source/core/dom/custom/CustomElementsRegistryTest.cpp
@@ -25,63 +25,21 @@
 
 namespace blink {
 
-class CustomElementsRegistryTestBase : public ::testing::Test {
+class CustomElementsRegistryTest : public ::testing::Test {
 protected:
-    virtual Document& document() = 0;
-    virtual CustomElementsRegistry& registry() = 0;
-
-    void collectCandidates(
-        const CustomElementDescriptor& desc,
-        HeapVector<Member<Element>>* elements)
+    void SetUp()
     {
-        registry().collectCandidates(desc, elements);
-    }
-};
-
-class CustomElementsRegistryTest : public CustomElementsRegistryTestBase {
-protected:
-    void SetUp() override
-    {
-        CustomElementsRegistryTestBase::SetUp();
-
-        m_document = HTMLDocument::create();
-        m_document->appendChild(CreateElement("html").inDocument(m_document));
-
-        m_registry = CustomElementsRegistry::create(m_document);
-    }
-
-    void TearDown() override
-    {
-        m_document = nullptr;
-        m_registry = nullptr;
-        CustomElementsRegistryTestBase::TearDown();
-    }
-
-    Document& document() override { return *m_document; }
-    CustomElementsRegistry& registry() override { return *m_registry; }
-
-private:
-    Persistent<Document> m_document;
-    Persistent<CustomElementsRegistry> m_registry;
-};
-
-class CustomElementsRegistryFrameTest : public CustomElementsRegistryTestBase {
-protected:
-    void SetUp() override
-    {
-        CustomElementsRegistryTestBase::SetUp();
         m_page.reset(DummyPageHolder::create(IntSize(1, 1)).release());
     }
 
-    void TearDown() override
+    void TearDown()
     {
         m_page = nullptr;
-        CustomElementsRegistryTestBase::TearDown();
     }
 
-    Document& document() override { return m_page->document(); }
+    Document& document() { return m_page->document(); }
 
-    CustomElementsRegistry& registry() override
+    CustomElementsRegistry& registry()
     {
         return *m_page->frame().localDOMWindow()->customElements();
     }
@@ -91,6 +49,13 @@
         return ScriptState::forMainWorld(&m_page->frame());
     }
 
+    void collectCandidates(
+        const CustomElementDescriptor& desc,
+        HeapVector<Member<Element>>* elements)
+    {
+        registry().collectCandidates(desc, elements);
+    }
+
     ShadowRoot* attachShadowTo(Element* element)
     {
         NonThrowableExceptionState noExceptions;
@@ -361,7 +326,7 @@
     }
 };
 
-TEST_F(CustomElementsRegistryFrameTest, define_upgradesInDocumentElements)
+TEST_F(CustomElementsRegistryTest, define_upgradesInDocumentElements)
 {
     ScriptForbiddenScope doNotRelyOnScript;
 
@@ -408,7 +373,7 @@
         << "upgrade should not invoke other callbacks";
 }
 
-TEST_F(CustomElementsRegistryFrameTest, attributeChangedCallback)
+TEST_F(CustomElementsRegistryTest, attributeChangedCallback)
 {
     ScriptForbiddenScope doNotRelyOnScript;
 
@@ -445,7 +410,7 @@
         << "upgrade should not invoke other callbacks";
 }
 
-TEST_F(CustomElementsRegistryFrameTest, disconnectedCallback)
+TEST_F(CustomElementsRegistryTest, disconnectedCallback)
 {
     ScriptForbiddenScope doNotRelyOnScript;
 
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
index 7379a49a1..2bc7c78 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.cpp
@@ -1328,7 +1328,12 @@
 CustomElementsRegistry* LocalDOMWindow::customElements() const
 {
     if (!m_customElements && m_document)
-        m_customElements = CustomElementsRegistry::create(document());
+        m_customElements = CustomElementsRegistry::create(this);
+    return m_customElements;
+}
+
+CustomElementsRegistry* LocalDOMWindow::maybeCustomElements() const
+{
     return m_customElements;
 }
 
diff --git a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
index d1db19f..94351da 100644
--- a/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
+++ b/third_party/WebKit/Source/core/frame/LocalDOMWindow.h
@@ -154,6 +154,7 @@
     void cancelIdleCallback(int id) override;
     CustomElementsRegistry* customElements(ScriptState*) const override;
     CustomElementsRegistry* customElements() const;
+    CustomElementsRegistry* maybeCustomElements() const;
 
     void registerProperty(DOMWindowProperty*);
     void unregisterProperty(DOMWindowProperty*);
diff --git a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
index b4b4d92..4c9e0d3 100644
--- a/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLLinkElement.cpp
@@ -473,7 +473,8 @@
             clearSheet();
         m_sheet = CSSStyleSheet::create(restoredSheet, m_owner);
         m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
-        m_sheet->setTitle(m_owner->title());
+        if (m_owner->isInDocumentTree())
+            m_sheet->setTitle(m_owner->title());
         setCrossOriginStylesheetStatus(m_sheet.get());
 
         m_loading = false;
@@ -494,7 +495,8 @@
 
     m_sheet = CSSStyleSheet::create(styleSheet, m_owner);
     m_sheet->setMediaQueries(MediaQuerySet::create(m_owner->media()));
-    m_sheet->setTitle(m_owner->title());
+    if (m_owner->isInDocumentTree())
+        m_sheet->setTitle(m_owner->title());
     setCrossOriginStylesheetStatus(m_sheet.get());
 
     styleSheet->parseAuthorStyleSheet(cachedStyleSheet, m_owner->document().getSecurityOrigin());
@@ -710,7 +712,7 @@
 
 void LinkStyle::setSheetTitle(const String& title)
 {
-    if (m_sheet)
+    if (m_sheet && m_owner->isInDocumentTree())
         m_sheet->setTitle(title);
 }
 
diff --git a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
index c8a3610..f989a92 100644
--- a/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
+++ b/third_party/WebKit/Source/core/html/HTMLStyleElement.cpp
@@ -60,7 +60,7 @@
 
 void HTMLStyleElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value)
 {
-    if (name == titleAttr && m_sheet) {
+    if (name == titleAttr && m_sheet && isInDocumentTree()) {
         m_sheet->setTitle(value);
     } else if (name == mediaAttr && isConnected() && document().isActive() && m_sheet) {
         m_sheet->setMediaQueries(MediaQuerySet::create(value));
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
index 33ce143..cf1b568 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp
@@ -26,6 +26,8 @@
 
 #include "core/html/parser/HTMLConstructionSite.h"
 
+#include "bindings/core/v8/Microtask.h"
+#include "bindings/core/v8/V8PerIsolateData.h"
 #include "core/HTMLElementFactory.h"
 #include "core/HTMLNames.h"
 #include "core/dom/Comment.h"
@@ -33,9 +35,15 @@
 #include "core/dom/DocumentType.h"
 #include "core/dom/Element.h"
 #include "core/dom/ElementTraversal.h"
+#include "core/dom/IgnoreDestructiveWriteCountIncrementer.h"
 #include "core/dom/ScriptLoader.h"
 #include "core/dom/TemplateContentDocumentFragment.h"
 #include "core/dom/Text.h"
+#include "core/dom/custom/CEReactionsScope.h"
+#include "core/dom/custom/CustomElementDefinition.h"
+#include "core/dom/custom/CustomElementDescriptor.h"
+#include "core/dom/custom/CustomElementsRegistry.h"
+#include "core/frame/LocalDOMWindow.h"
 #include "core/frame/LocalFrame.h"
 #include "core/html/HTMLFormElement.h"
 #include "core/html/HTMLHtmlElement.h"
@@ -44,6 +52,7 @@
 #include "core/html/HTMLTemplateElement.h"
 #include "core/html/parser/AtomicHTMLToken.h"
 #include "core/html/parser/HTMLParserIdioms.h"
+#include "core/html/parser/HTMLParserReentryPermit.h"
 #include "core/html/parser/HTMLStackItem.h"
 #include "core/html/parser/HTMLToken.h"
 #include "core/loader/FrameLoader.h"
@@ -314,8 +323,9 @@
     // We might be detached now.
 }
 
-HTMLConstructionSite::HTMLConstructionSite(Document& document, ParserContentPolicy parserContentPolicy)
-    : m_document(&document)
+HTMLConstructionSite::HTMLConstructionSite(HTMLParserReentryPermit* reentryPermit, Document& document, ParserContentPolicy parserContentPolicy)
+    : m_reentryPermit(reentryPermit)
+    , m_document(&document)
     , m_attachmentRoot(document)
     , m_parserContentPolicy(parserContentPolicy)
     , m_isParsingFragment(false)
@@ -747,17 +757,111 @@
     return currentNode()->document();
 }
 
+// "look up a custom element definition" for a token
+// https://html.spec.whatwg.org/#look-up-a-custom-element-definition
+CustomElementDefinition* HTMLConstructionSite::lookUpCustomElementDefinition(Document& document, AtomicHTMLToken* token)
+{
+    // "2. If document does not have a browsing context, return null."
+    LocalDOMWindow* window = document.domWindow();
+    if (!window)
+        return nullptr;
+
+    // "3. Let registry be document's browsing context's Window's
+    // CustomElementsRegistry object."
+    CustomElementsRegistry* registry = window->maybeCustomElements();
+    if (!registry)
+        return nullptr;
+
+    const AtomicString& localName = token->name();
+    const Attribute* isAttribute = token->getAttributeItem(HTMLNames::isAttr);
+    const AtomicString& name = isAttribute ? isAttribute->value() : localName;
+    CustomElementDescriptor descriptor(name, localName);
+
+    // 4.-6.
+    return registry->definitionFor(descriptor);
+}
+
+// "create an element for a token"
+// https://html.spec.whatwg.org/#create-an-element-for-the-token
+// TODO(dominicc): When form association is separate from creation,
+// unify this with foreign element creation. Add a namespace parameter
+// and check for HTML namespace to lookupCustomElementDefinition.
 HTMLElement* HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token)
 {
+    // "1. Let document be intended parent's node document."
     Document& document = ownerDocumentForCurrentNode();
+
     // Only associate the element with the current form if we're creating the new element
     // in a document with a browsing context (rather than in <template> contents).
+    // TODO(dominicc): Change form to happen after element creation when
+    // implementing customized built-in elements.
     HTMLFormElement* form = document.frame() ? m_form.get() : nullptr;
-    // FIXME: This can't use HTMLConstructionSite::createElement because we
-    // have to pass the current form element.  We should rework form association
-    // to occur after construction to allow better code sharing here.
-    HTMLElement* element = HTMLElementFactory::createHTMLElement(token->name(), document, form, getCreateElementFlags());
-    setAttributes(element, token, m_parserContentPolicy);
+
+    // "2. Let local name be the tag name of the token."
+    // "3. Let is be the value of the "is" attribute in the giev token ..." etc.
+    // "4. Let definition be the result of looking up a custom element ..." etc.
+    CustomElementDefinition* definition = m_isParsingFragment ? nullptr : lookUpCustomElementDefinition(document, token);
+    // "5. If definition is non-null and the parser was not originally created
+    // for the HTML fragment parsing algorithm, then let will execute script
+    // be true."
+    bool willExecuteScript = definition && !m_isParsingFragment;
+
+    HTMLElement* element;
+
+    if (willExecuteScript) {
+        // "6.1 Increment the parser's script nesting level."
+        HTMLParserReentryPermit::ScriptNestingLevelIncrementer incrementScriptNestingLevel = m_reentryPermit->incrementScriptNestingLevel();
+
+        // "6.2 Set the parser pause flag to true."
+        m_reentryPermit->pause();
+
+        // TODO(dominicc): Change this once resolved:
+        // https://github.com/whatwg/html/issues/1630
+        IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWrites(
+            &document);
+
+        // "6.3 If the JavaScript execution context stack is empty,
+        // then perform a microtask checkpoint."
+
+        // TODO(dominicc): This is the way the Blink HTML parser
+        // performs checkpoints, but note the spec is different--it
+        // talks about the JavaScript stack, not the script nesting
+        // level.
+        if (1u == m_reentryPermit->scriptNestingLevel())
+            Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate());
+
+        // "6.4 Push a new element queue onto the custom element
+        // reactions stack."
+        CEReactionsScope reactions;
+
+        // 7.
+        QualifiedName elementQName(nullAtom, token->name(), HTMLNames::xhtmlNamespaceURI);
+        element = definition->createElementSync(document, elementQName);
+
+        // "8. Append each attribute in the given token to element."
+        // We don't use setAttributes here because the custom element
+        // constructor may have manipulated attributes.
+        for (const auto& attribute : token->attributes())
+            element->setAttribute(attribute.name(), attribute.value());
+
+        // "9. If will execute script is true, then ..." etc. The
+        // CEReactionsScope and ScriptNestingLevelIncrementer
+        // destructors implement steps 9.1-4.
+    } else {
+        // FIXME: This can't use
+        // HTMLConstructionSite::createElement because we have to
+        // pass the current form element. We should rework form
+        // association to occur after construction to allow better
+        // code sharing here.
+        element = HTMLElementFactory::createHTMLElement(token->name(), document, form, getCreateElementFlags());
+
+        // "8. Append each attribute in the given token to element."
+        setAttributes(element, token, m_parserContentPolicy);
+    }
+
+    // TODO(dominicc): Implement steps 10-12 when customized built-in
+    // elements are implemented.
+
     return element;
 }
 
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h
index 3d661623..1d175f36 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h
@@ -31,9 +31,8 @@
 #include "core/dom/ParserContentPolicy.h"
 #include "core/html/parser/HTMLElementStack.h"
 #include "core/html/parser/HTMLFormattingElementList.h"
+#include "platform/heap/Handle.h"
 #include "wtf/Noncopyable.h"
-#include "wtf/PassRefPtr.h"
-#include "wtf/RefPtr.h"
 #include "wtf/Vector.h"
 #include "wtf/text/StringBuilder.h"
 
@@ -101,15 +100,17 @@
 };
 
 class AtomicHTMLToken;
+class CustomElementDefinition;
 class Document;
 class Element;
 class HTMLFormElement;
+class HTMLParserReentryPermit;
 
 class HTMLConstructionSite final {
     WTF_MAKE_NONCOPYABLE(HTMLConstructionSite);
     DISALLOW_NEW();
 public:
-    HTMLConstructionSite(Document&, ParserContentPolicy);
+    HTMLConstructionSite(HTMLParserReentryPermit*, Document&, ParserContentPolicy);
     ~HTMLConstructionSite();
     DECLARE_TRACE();
 
@@ -243,6 +244,9 @@
     void executeTask(HTMLConstructionSiteTask&);
     void queueTask(const HTMLConstructionSiteTask&);
 
+    CustomElementDefinition* lookUpCustomElementDefinition(Document&, AtomicHTMLToken*);
+
+    HTMLParserReentryPermit* m_reentryPermit;
     Member<Document> m_document;
 
     // This is the root ContainerNode to which the parser attaches all newly
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
index 20960c46..1a42b3b 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp
@@ -92,7 +92,7 @@
 HTMLDocumentParser::HTMLDocumentParser(HTMLDocument& document, ParserSynchronizationPolicy syncPolicy)
     : HTMLDocumentParser(document, AllowScriptingContent, syncPolicy)
 {
-    m_scriptRunner = HTMLScriptRunner::create(&document, this);
+    m_scriptRunner = HTMLScriptRunner::create(reentryPermit(), &document, this);
     m_treeBuilder = HTMLTreeBuilder::create(this, document, AllowScriptingContent, m_options);
 }
 
@@ -110,6 +110,7 @@
 HTMLDocumentParser::HTMLDocumentParser(Document& document, ParserContentPolicy contentPolicy, ParserSynchronizationPolicy syncPolicy)
     : ScriptableDocumentParser(document, contentPolicy)
     , m_options(&document)
+    , m_reentryPermit(HTMLParserReentryPermit::create())
     , m_token(syncPolicy == ForceSynchronousParsing ? wrapUnique(new HTMLToken) : nullptr)
     , m_tokenizer(syncPolicy == ForceSynchronousParsing ? HTMLTokenizer::create(m_options) : nullptr)
     , m_loadingTaskRunner(TaskRunnerHelper::getLoadingTaskRunner(&document)->clone())
@@ -955,7 +956,7 @@
     // never be possible to end up with both objects holding a blocking script.
     ASSERT(!(treeBuilderHasBlockingScript && scriptRunnerHasBlockingScript));
     // If either object has a blocking script, the parser should be paused.
-    return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript;
+    return treeBuilderHasBlockingScript || scriptRunnerHasBlockingScript || m_reentryPermit->parserPauseFlag();
 }
 
 void HTMLDocumentParser::resumeParsingAfterScriptExecution()
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
index e83f3bb..84a12b1 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h
@@ -35,6 +35,7 @@
 #include "core/html/parser/CompactHTMLToken.h"
 #include "core/html/parser/HTMLInputStream.h"
 #include "core/html/parser/HTMLParserOptions.h"
+#include "core/html/parser/HTMLParserReentryPermit.h"
 #include "core/html/parser/HTMLPreloadScanner.h"
 #include "core/html/parser/HTMLScriptRunnerHost.h"
 #include "core/html/parser/HTMLSourceTracker.h"
@@ -47,6 +48,7 @@
 #include "core/html/parser/XSSAuditorDelegate.h"
 #include "platform/text/SegmentedString.h"
 #include "wtf/Deque.h"
+#include "wtf/RefPtr.h"
 #include "wtf/WeakPtr.h"
 #include "wtf/text/TextPosition.h"
 #include <memory>
@@ -95,6 +97,8 @@
     void suspendScheduledTasks() final;
     void resumeScheduledTasks() final;
 
+    HTMLParserReentryPermit* reentryPermit() { return m_reentryPermit.get(); }
+
     struct TokenizedChunk {
         USING_FAST_MALLOC(TokenizedChunk);
     public:
@@ -204,6 +208,7 @@
 
     HTMLParserOptions m_options;
     HTMLInputStream m_input;
+    RefPtr<HTMLParserReentryPermit> m_reentryPermit;
 
     std::unique_ptr<HTMLToken> m_token;
     std::unique_ptr<HTMLTokenizer> m_tokenizer;
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.cpp b/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.cpp
new file mode 100644
index 0000000..dc609100
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.cpp
@@ -0,0 +1,18 @@
+// 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/html/parser/HTMLParserReentryPermit.h"
+
+namespace blink {
+
+PassRefPtr<HTMLParserReentryPermit> HTMLParserReentryPermit::create()
+{
+    return adoptRef(new HTMLParserReentryPermit());
+}
+
+HTMLParserReentryPermit::HTMLParserReentryPermit()
+    : m_scriptNestingLevel(0)
+    , m_parserPauseFlag(false) {}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.h b/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.h
new file mode 100644
index 0000000..4538b4c
--- /dev/null
+++ b/third_party/WebKit/Source/core/html/parser/HTMLParserReentryPermit.h
@@ -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.
+
+#ifndef HTMLParserReentryPermit_h
+#define HTMLParserReentryPermit_h
+
+#include "base/macros.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefCounted.h"
+
+namespace blink {
+
+// The HTML spec for parsing controls reentering the parser from
+// script with the "parser pause flag" and "script nesting level."
+//
+// The parser pause flag puts a brake on whether the tokenizer will
+// produce more tokens. When the parser is paused, nested invocations
+// of the tokenizer unwind.
+//
+// The script nesting level is incremented and decremented any time
+// the parser causes script to run. The script nesting level:
+//
+// - May prevent document.open from blowing away the document.
+//
+// - Governs whether a script element becomes the "pending
+//   parsing-blocking script." The pending parsing-blocking script in
+//   turn affects whether document.write reenters the parser.
+//
+// Clearing the parser pause flag is simple: Whenever the script
+// nesting level hits zero, the parser pause flag is cleared. However
+// setting the parser pause flag is subtle.
+//
+// Processing a typical script end tag, or running a chain of pending
+// parser-blocking scripts after that, does not set the parser pause
+// flag. However recursively parsing end script tags, or running
+// custom element constructors, does set the parser pause flag.
+class HTMLParserReentryPermit final : public RefCounted<HTMLParserReentryPermit> {
+public:
+    static PassRefPtr<HTMLParserReentryPermit> create();
+    ~HTMLParserReentryPermit() = default;
+
+    unsigned scriptNestingLevel() const { return m_scriptNestingLevel; }
+    bool parserPauseFlag() const { return m_parserPauseFlag; }
+    void pause()
+    {
+        CHECK(m_scriptNestingLevel);
+        m_parserPauseFlag = true;
+    }
+
+    class ScriptNestingLevelIncrementer final {
+        STACK_ALLOCATED();
+    public:
+        explicit ScriptNestingLevelIncrementer(HTMLParserReentryPermit* permit)
+            : m_permit(permit)
+        {
+            m_permit->m_scriptNestingLevel++;
+        }
+
+        ScriptNestingLevelIncrementer(ScriptNestingLevelIncrementer&&)
+            = default;
+
+        ~ScriptNestingLevelIncrementer()
+        {
+            m_permit->m_scriptNestingLevel--;
+            if (!m_permit->m_scriptNestingLevel)
+                m_permit->m_parserPauseFlag = false;
+        }
+
+    private:
+        HTMLParserReentryPermit* m_permit;
+
+        DISALLOW_COPY_AND_ASSIGN(ScriptNestingLevelIncrementer);
+    };
+
+    ScriptNestingLevelIncrementer incrementScriptNestingLevel()
+    {
+        return ScriptNestingLevelIncrementer(this);
+    }
+
+private:
+    HTMLParserReentryPermit();
+
+    // https://html.spec.whatwg.org/#script-nesting-level
+    unsigned m_scriptNestingLevel;
+
+    // https://html.spec.whatwg.org/#parser-pause-flag
+    bool m_parserPauseFlag;
+
+    DISALLOW_COPY_AND_ASSIGN(HTMLParserReentryPermit);
+};
+
+} // namespace blink
+
+#endif // HTMLParserReentryPermit_h
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
index d386b0977..05c63f6 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp
@@ -133,11 +133,11 @@
 
 using namespace HTMLNames;
 
-HTMLScriptRunner::HTMLScriptRunner(Document* document, HTMLScriptRunnerHost* host)
-    : m_document(document)
+HTMLScriptRunner::HTMLScriptRunner(HTMLParserReentryPermit* reentryPermit, Document* document, HTMLScriptRunnerHost* host)
+    : m_reentryPermit(reentryPermit)
+    , m_document(document)
     , m_host(host)
     , m_parserBlockingScript(PendingScript::create(nullptr, nullptr))
-    , m_scriptNestingLevel(0)
     , m_hasScriptsWaitingForResources(false)
 {
     ASSERT(m_host);
@@ -164,6 +164,9 @@
         pendingScript->releaseElementAndClear();
     }
     m_document = nullptr;
+    // m_reentryPermit is not cleared here, because the script runner
+    // may continue to run pending scripts after the parser has
+    // detached.
 }
 
 bool HTMLScriptRunner::isPendingScriptReady(const PendingScript* script)
@@ -208,7 +211,7 @@
     // Clear the pending script before possible re-entrancy from executeScript()
     Element* element = pendingScript->releaseElementAndClear();
     if (ScriptLoader* scriptLoader = toScriptLoaderIfPossible(element)) {
-        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+        HTMLParserReentryPermit::ScriptNestingLevelIncrementer nestingLevelIncrementer = m_reentryPermit->incrementScriptNestingLevel();
         IgnoreDestructiveWriteCountIncrementer ignoreDestructiveWriteCountIncrementer(m_document);
         if (errorOccurred) {
             TRACE_EVENT_WITH_FLOW1("blink", "HTMLScriptRunner ExecuteScriptFailed", element, TRACE_EVENT_FLAG_FLOW_IN,
@@ -419,7 +422,7 @@
             Microtask::performCheckpoint(V8PerIsolateData::mainThreadIsolate());
 
         InsertionPointRecord insertionPointRecord(m_host->inputStream());
-        NestingLevelIncrementer nestingLevelIncrementer(m_scriptNestingLevel);
+        HTMLParserReentryPermit::ScriptNestingLevelIncrementer nestingLevelIncrementer = m_reentryPermit->incrementScriptNestingLevel();
 
         scriptLoader->prepareScript(scriptStartPosition);
 
@@ -429,11 +432,11 @@
         if (scriptLoader->willExecuteWhenDocumentFinishedParsing()) {
             requestDeferredScript(script);
         } else if (scriptLoader->readyToBeParserExecuted()) {
-            if (m_scriptNestingLevel == 1) {
+            if (m_reentryPermit->scriptNestingLevel() == 1u) {
                 m_parserBlockingScript->setElement(script);
                 m_parserBlockingScript->setStartingPosition(scriptStartPosition);
             } else {
-                ASSERT(m_scriptNestingLevel > 1);
+                DCHECK_GT(m_reentryPermit->scriptNestingLevel(), 1u);
                 m_parserBlockingScript->releaseElementAndClear();
                 ScriptSourceCode sourceCode(script->textContent(), documentURLForScriptExecution(m_document), scriptStartPosition);
                 doExecuteScript(script, sourceCode, scriptStartPosition);
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
index eeb2959..c69e4e06 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
+++ b/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.h
@@ -29,9 +29,10 @@
 #include "bindings/core/v8/ScriptStreamer.h"
 #include "core/dom/PendingScript.h"
 #include "core/fetch/ResourceClient.h"
+#include "core/html/parser/HTMLParserReentryPermit.h"
 #include "platform/heap/Handle.h"
 #include "wtf/Deque.h"
-#include "wtf/PassRefPtr.h"
+#include "wtf/RefPtr.h"
 #include "wtf/text/TextPosition.h"
 
 namespace blink {
@@ -46,9 +47,9 @@
     USING_GARBAGE_COLLECTED_MIXIN(HTMLScriptRunner);
     USING_PRE_FINALIZER(HTMLScriptRunner, detach);
 public:
-    static HTMLScriptRunner* create(Document* document, HTMLScriptRunnerHost* host)
+    static HTMLScriptRunner* create(HTMLParserReentryPermit* reentryPermit, Document* document, HTMLScriptRunnerHost* host)
     {
-        return new HTMLScriptRunner(document, host);
+        return new HTMLScriptRunner(reentryPermit, document, host);
     }
     ~HTMLScriptRunner();
 
@@ -63,7 +64,7 @@
     bool executeScriptsWaitingForParsing();
 
     bool hasParserBlockingScript() const;
-    bool isExecutingScript() const { return !!m_scriptNestingLevel; }
+    bool isExecutingScript() const { return !!m_reentryPermit->scriptNestingLevel(); }
 
     // ResourceClient
     void notifyFinished(Resource*) override;
@@ -72,7 +73,7 @@
     DECLARE_TRACE();
 
 private:
-    HTMLScriptRunner(Document*, HTMLScriptRunnerHost*);
+    HTMLScriptRunner(HTMLParserReentryPermit*, Document*, HTMLScriptRunnerHost*);
 
     void executeParsingBlockingScript();
     void executePendingScriptAndDispatchEvent(PendingScript*, ScriptStreamer::Type);
@@ -88,12 +89,12 @@
 
     void stopWatchingResourceForLoad(Resource*);
 
+    RefPtr<HTMLParserReentryPermit> m_reentryPermit;
     Member<Document> m_document;
     Member<HTMLScriptRunnerHost> m_host;
     Member<PendingScript> m_parserBlockingScript;
     // http://www.whatwg.org/specs/web-apps/current-work/#list-of-scripts-that-will-execute-when-the-document-has-finished-parsing
     HeapDeque<Member<PendingScript>> m_scriptsToExecuteAfterParsing;
-    unsigned m_scriptNestingLevel;
 
     // We only want stylesheet loads to trigger script execution if script
     // execution is currently stopped due to stylesheet loads, otherwise we'd
diff --git a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
index ff36b58..72ac560 100644
--- a/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp
@@ -267,7 +267,7 @@
 #if ENABLE(ASSERT)
     , m_isAttached(true)
 #endif
-    , m_tree(document, parserContentPolicy)
+    , m_tree(parser->reentryPermit(), document, parserContentPolicy)
     , m_insertionMode(InitialMode)
     , m_originalInsertionMode(InitialMode)
     , m_shouldSkipLeadingNewline(false)
@@ -326,8 +326,9 @@
 void HTMLTreeBuilder::detach()
 {
 #if ENABLE(ASSERT)
-    // This call makes little sense in fragment mode, but for consistency
-    // DocumentParser expects detach() to always be called before it's destroyed.
+    // This call makes little sense in fragment mode, but for
+    // consistency DocumentParser expects detach() to always be called
+    // before it's destroyed.
     m_isAttached = false;
 #endif
     // HTMLConstructionSite might be on the callstack when detach() is called
@@ -619,7 +620,12 @@
         m_tree.openElements()->bodyElement()->remove(ASSERT_NO_EXCEPTION);
         m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement());
         m_tree.openElements()->popHTMLBodyElement();
-        ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement());
+
+        // Note: in the fragment case the root is a DocumentFragment instead of
+        // a proper html element which is a quirk in Blink's implementation.
+        DCHECK(!isParsingTemplateContents());
+        DCHECK(!isParsingFragment() || toDocumentFragment(m_tree.openElements()->topNode()));
+        DCHECK(isParsingFragment() || m_tree.openElements()->top() == m_tree.openElements()->htmlElement());
         m_tree.insertHTMLElement(token);
         setInsertionMode(InFramesetMode);
         return;
diff --git a/third_party/WebKit/Source/core/svg/SVGStyleElement.cpp b/third_party/WebKit/Source/core/svg/SVGStyleElement.cpp
index e7a2086..8a9ad0bd 100644
--- a/third_party/WebKit/Source/core/svg/SVGStyleElement.cpp
+++ b/third_party/WebKit/Source/core/svg/SVGStyleElement.cpp
@@ -100,7 +100,7 @@
 void SVGStyleElement::parseAttribute(const QualifiedName& name, const AtomicString& oldValue, const AtomicString& value)
 {
     if (name == SVGNames::titleAttr) {
-        if (m_sheet)
+        if (m_sheet && isInDocumentTree())
             m_sheet->setTitle(value);
 
         return;
diff --git a/third_party/WebKit/Source/platform/SharedBuffer.cpp b/third_party/WebKit/Source/platform/SharedBuffer.cpp
index 02006e7..6ce6466 100644
--- a/third_party/WebKit/Source/platform/SharedBuffer.cpp
+++ b/third_party/WebKit/Source/platform/SharedBuffer.cpp
@@ -240,25 +240,27 @@
     return 0;
 }
 
-bool SharedBuffer::getAsBytesInternal(void* dest, size_t byteLength) const
+bool SharedBuffer::getAsBytesInternal(void* dest, size_t loadPosition, size_t byteLength) const
 {
-    if (!dest || byteLength != size())
+    if (!dest)
         return false;
 
-    const char* segment = 0;
-    size_t position = 0;
-    while (size_t segmentSize = getSomeDataInternal(segment, position)) {
-        memcpy(static_cast<char*>(dest) + position, segment, segmentSize);
-        position += segmentSize;
+    const char* segment = nullptr;
+    size_t writePosition = 0;
+    while (byteLength > 0) {
+        size_t loadSize = getSomeDataInternal(segment, loadPosition);
+        if (loadSize == 0)
+            break;
+
+        if (byteLength < loadSize)
+            loadSize = byteLength;
+        memcpy(static_cast<char*>(dest) + writePosition, segment, loadSize);
+        loadPosition += loadSize;
+        writePosition += loadSize;
+        byteLength -= loadSize;
     }
 
-    if (position != byteLength) {
-        ASSERT_NOT_REACHED();
-        // Don't return the incomplete data.
-        return false;
-    }
-
-    return true;
+    return byteLength == 0;
 }
 
 sk_sp<SkData> SharedBuffer::getAsSkData() const
diff --git a/third_party/WebKit/Source/platform/SharedBuffer.h b/third_party/WebKit/Source/platform/SharedBuffer.h
index b03aa858..a8d96c0 100644
--- a/third_party/WebKit/Source/platform/SharedBuffer.h
+++ b/third_party/WebKit/Source/platform/SharedBuffer.h
@@ -125,7 +125,20 @@
     bool getAsBytes(void* dest, STRICTLY_TYPED_ARG(byteLength)) const
     {
         STRICT_ARG_TYPE(size_t);
-        return getAsBytesInternal(dest, byteLength);
+        if (byteLength != size())
+            return false;
+
+        return getAsBytesInternal(dest, 0, byteLength);
+    }
+
+    // Copies "byteLength" bytes from "position"-th bytes (0 origin) of the content
+    // data into "dest" as a flat buffer,
+    // Returns true on success, otherwise the content of "dest" is not guaranteed.
+    HAS_STRICTLY_TYPED_ARG
+    bool getPartAsBytes(void* dest, STRICTLY_TYPED_ARG(position), STRICTLY_TYPED_ARG(byteLength)) const
+    {
+        STRICT_ARG_TYPE(size_t);
+        return getAsBytesInternal(dest, position, byteLength);
     }
 
     // Creates an SkData and copies this SharedBuffer's contents to that
@@ -155,7 +168,7 @@
     void mergeSegmentsIntoBuffer() const;
 
     void appendInternal(const char* data, size_t);
-    bool getAsBytesInternal(void* dest, size_t) const;
+    bool getAsBytesInternal(void* dest, size_t, size_t) const;
     size_t getSomeDataInternal(const char*& data, size_t position) const;
 
     size_t m_size;
diff --git a/third_party/WebKit/Source/platform/SharedBufferTest.cpp b/third_party/WebKit/Source/platform/SharedBufferTest.cpp
index a93154e..904b274 100644
--- a/third_party/WebKit/Source/platform/SharedBufferTest.cpp
+++ b/third_party/WebKit/Source/platform/SharedBufferTest.cpp
@@ -59,6 +59,32 @@
     EXPECT_EQ(0, memcmp(expectedConcatenation, data.get(), strlen(expectedConcatenation)));
 }
 
+TEST(SharedBufferTest, getPartAsBytes)
+{
+    char testData0[] = "Hello";
+    char testData1[] = "World";
+    char testData2[] = "Goodbye";
+
+    RefPtr<SharedBuffer> sharedBuffer = SharedBuffer::create(testData0, strlen(testData0));
+    sharedBuffer->append(testData1, strlen(testData1));
+    sharedBuffer->append(testData2, strlen(testData2));
+
+    struct TestData {
+        size_t position;
+        size_t size;
+        const char* expected;
+    } testData[] = {
+        {0, 17, "HelloWorldGoodbye"},
+        {0, 7, "HelloWo"},
+        {4, 7, "oWorldG"},
+    };
+    for (TestData& test : testData) {
+        std::unique_ptr<char[]> data = wrapArrayUnique(new char[test.size]);
+        ASSERT_TRUE(sharedBuffer->getPartAsBytes(data.get(), test.position, test.size));
+        EXPECT_EQ(0, memcmp(test.expected, data.get(), test.size));
+    }
+}
+
 TEST(SharedBufferTest, getAsBytesLargeSegments)
 {
     Vector<char> vector0(0x4000);
diff --git a/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp b/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
index 63becca..e9aaf24 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorAnimation.cpp
@@ -133,7 +133,7 @@
     DCHECK_EQ(cc::AnimationCurve::FLOAT, curve->Type());
 
     auto keyframedCurve = base::WrapUnique(static_cast<cc::KeyframedFloatAnimationCurve*>(curve->Clone().release()));
-    return CompositorFloatAnimationCurve::CreateForTesting(std::move(keyframedCurve));
+    return CompositorFloatAnimationCurve::createForTesting(std::move(keyframedCurve));
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
index df10488..645e227 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.cpp
@@ -20,12 +20,9 @@
 {
 }
 
-void CompositorFilterAnimationCurve::addKeyframe(const CompositorFilterKeyframe& keyframe, const TimingFunction& timingFunction)
+void CompositorFilterAnimationCurve::addKeyframe(const CompositorFilterKeyframe& keyframe)
 {
-    const cc::FilterOperations& filterOperations = keyframe.value().asFilterOperations();
-    m_curve->AddKeyframe(cc::FilterKeyframe::Create(
-        base::TimeDelta::FromSecondsD(keyframe.time()), filterOperations,
-        timingFunction.cloneToCC()));
+    m_curve->AddKeyframe(keyframe.cloneToCC());
 }
 
 void CompositorFilterAnimationCurve::setTimingFunction(const TimingFunction& timingFunction)
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h
index a2d95ee9..2a6ae5f 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterAnimationCurve.h
@@ -33,7 +33,7 @@
     }
     ~CompositorFilterAnimationCurve() override;
 
-    void addKeyframe(const CompositorFilterKeyframe&, const TimingFunction&);
+    void addKeyframe(const CompositorFilterKeyframe&);
     void setTimingFunction(const TimingFunction&);
 
     // blink::CompositorAnimationCurve implementation.
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
index d67ba928..3cabf96 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.cpp
@@ -4,19 +4,33 @@
 
 #include "platform/animation/CompositorFilterKeyframe.h"
 
+#include "platform/animation/TimingFunction.h"
 #include <memory>
 
 namespace blink {
 
-CompositorFilterKeyframe::CompositorFilterKeyframe(double time, std::unique_ptr<CompositorFilterOperations> value)
-    : m_time(time)
-    , m_value(std::move(value))
+CompositorFilterKeyframe::CompositorFilterKeyframe(double time, const CompositorFilterOperations& value, const TimingFunction& timingFunction)
+    : m_filterKeyframe(cc::FilterKeyframe::Create(base::TimeDelta::FromSecondsD(time), value.asFilterOperations(), timingFunction.cloneToCC()))
 {
 }
 
 CompositorFilterKeyframe::~CompositorFilterKeyframe()
 {
-    m_value.reset();
+}
+
+double CompositorFilterKeyframe::time() const
+{
+    return m_filterKeyframe->Time().InSecondsF();
+}
+
+const cc::TimingFunction* CompositorFilterKeyframe::ccTimingFunction() const
+{
+    return m_filterKeyframe->timing_function();
+}
+
+std::unique_ptr<cc::FilterKeyframe> CompositorFilterKeyframe::cloneToCC() const
+{
+    return m_filterKeyframe->Clone();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.h b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.h
index bbecf3fa..dab49b3 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorFilterKeyframe.h
@@ -5,24 +5,30 @@
 #ifndef CompositorFilterKeyframe_h
 #define CompositorFilterKeyframe_h
 
+#include "cc/animation/keyframed_animation_curve.h"
 #include "platform/PlatformExport.h"
+#include "platform/animation/CompositorKeyframe.h"
 #include "platform/graphics/CompositorFilterOperations.h"
-#include <memory>
+#include "wtf/Noncopyable.h"
 
 namespace blink {
 
-class PLATFORM_EXPORT CompositorFilterKeyframe {
+class TimingFunction;
+
+class PLATFORM_EXPORT CompositorFilterKeyframe : public CompositorKeyframe {
+    WTF_MAKE_NONCOPYABLE(CompositorFilterKeyframe);
 public:
-    CompositorFilterKeyframe(double time, std::unique_ptr<CompositorFilterOperations>);
+    CompositorFilterKeyframe(double time, const CompositorFilterOperations& value, const TimingFunction&);
     ~CompositorFilterKeyframe();
 
-    double time() const { return m_time; }
+    std::unique_ptr<cc::FilterKeyframe> cloneToCC() const;
 
-    const CompositorFilterOperations& value() const { return *m_value.get(); }
+    // CompositorKeyframe implementation.
+    double time() const override;
+    const cc::TimingFunction* ccTimingFunction() const override;
 
 private:
-    double m_time;
-    std::unique_ptr<CompositorFilterOperations> m_value;
+    std::unique_ptr<cc::FilterKeyframe> m_filterKeyframe;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
index 88874c1..7640ac8 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.cpp
@@ -26,56 +26,27 @@
 {
 }
 
-std::unique_ptr<CompositorFloatAnimationCurve> CompositorFloatAnimationCurve::CreateForTesting(std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve)
+std::unique_ptr<CompositorFloatAnimationCurve> CompositorFloatAnimationCurve::createForTesting(std::unique_ptr<cc::KeyframedFloatAnimationCurve> curve)
 {
     return wrapUnique(new CompositorFloatAnimationCurve(std::move(curve)));
 }
 
-Vector<CompositorFloatKeyframe> CompositorFloatAnimationCurve::keyframesForTesting() const
+CompositorFloatAnimationCurve::Keyframes CompositorFloatAnimationCurve::keyframesForTesting() const
 {
-    Vector<CompositorFloatKeyframe> keyframes;
-    for (const auto& ccKeyframe : m_curve->keyframes_for_testing()) {
-        CompositorFloatKeyframe keyframe(ccKeyframe->Time().InSecondsF(), ccKeyframe->Value());
-        keyframes.append(keyframe);
-    }
+    Keyframes keyframes;
+    for (const auto& ccKeyframe : m_curve->keyframes_for_testing())
+        keyframes.append(wrapUnique(new CompositorFloatKeyframe(ccKeyframe->Clone())));
     return keyframes;
 }
 
-CubicBezierTimingFunction::EaseType CompositorFloatAnimationCurve::getCurveEaseTypeForTesting() const
+PassRefPtr<TimingFunction> CompositorFloatAnimationCurve::getTimingFunctionForTesting() const
 {
-    const cc::TimingFunction* timingFunction = m_curve->timing_function_for_testing();
-    DCHECK(timingFunction);
-    DCHECK_EQ(timingFunction->GetType(), cc::TimingFunction::Type::CUBIC_BEZIER);
-    auto cubicTimingFunction = static_cast<const cc::CubicBezierTimingFunction*>(timingFunction);
-    return cubicTimingFunction->ease_type();
+    return createCompositorTimingFunctionFromCC(m_curve->timing_function_for_testing());
 }
 
-bool CompositorFloatAnimationCurve::curveHasLinearTimingFunctionForTesting() const
+void CompositorFloatAnimationCurve::addKeyframe(const CompositorFloatKeyframe& keyframe)
 {
-    return !m_curve->timing_function_for_testing();
-}
-
-CubicBezierTimingFunction::EaseType CompositorFloatAnimationCurve::getKeyframeEaseTypeForTesting(unsigned long index) const
-{
-    DCHECK_LT(index, m_curve->keyframes_for_testing().size());
-    const cc::TimingFunction* timingFunction = m_curve->keyframes_for_testing()[index]->timing_function();
-    DCHECK(timingFunction);
-    DCHECK_EQ(timingFunction->GetType(), cc::TimingFunction::Type::CUBIC_BEZIER);
-    auto cubicTimingFunction = static_cast<const cc::CubicBezierTimingFunction*>(timingFunction);
-    return cubicTimingFunction->ease_type();
-}
-
-bool CompositorFloatAnimationCurve::keyframeHasLinearTimingFunctionForTesting(unsigned long index) const
-{
-    DCHECK_LT(index, m_curve->keyframes_for_testing().size());
-    return !m_curve->keyframes_for_testing()[index]->timing_function();
-}
-
-void CompositorFloatAnimationCurve::addKeyframe(const CompositorFloatKeyframe& keyframe, const TimingFunction& timingFunction)
-{
-    m_curve->AddKeyframe(cc::FloatKeyframe::Create(
-        base::TimeDelta::FromSecondsD(keyframe.time), keyframe.value,
-        timingFunction.cloneToCC()));
+    m_curve->AddKeyframe(keyframe.cloneToCC());
 }
 
 void CompositorFloatAnimationCurve::setTimingFunction(const TimingFunction& timingFunction)
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h
index 00b6312f..1b82b90 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurve.h
@@ -10,6 +10,7 @@
 #include "platform/animation/CompositorFloatKeyframe.h"
 #include "platform/animation/TimingFunction.h"
 #include "wtf/Noncopyable.h"
+#include "wtf/PassRefPtr.h"
 #include "wtf/PtrUtil.h"
 #include "wtf/Vector.h"
 #include <memory>
@@ -19,7 +20,7 @@
 }
 
 namespace blink {
-struct CompositorFloatKeyframe;
+class CompositorFloatKeyframe;
 }
 
 namespace blink {
@@ -35,23 +36,20 @@
 
     ~CompositorFloatAnimationCurve() override;
 
-    static std::unique_ptr<CompositorFloatAnimationCurve> CreateForTesting(std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
-    Vector<CompositorFloatKeyframe> keyframesForTesting() const;
-
-    // TODO(loyso): Erase these methods once blink/cc timing functions unified.
-    CubicBezierTimingFunction::EaseType getCurveEaseTypeForTesting() const;
-    bool curveHasLinearTimingFunctionForTesting() const;
-    CubicBezierTimingFunction::EaseType getKeyframeEaseTypeForTesting(unsigned long index) const;
-    bool keyframeHasLinearTimingFunctionForTesting(unsigned long index) const;
-
-    void addKeyframe(const CompositorFloatKeyframe&, const TimingFunction&);
+    void addKeyframe(const CompositorFloatKeyframe&);
     void setTimingFunction(const TimingFunction&);
-
     float getValue(double time) const;
 
     // CompositorAnimationCurve implementation.
     std::unique_ptr<cc::AnimationCurve> cloneToAnimationCurve() const override;
 
+    static std::unique_ptr<CompositorFloatAnimationCurve> createForTesting(std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
+
+    using Keyframes = Vector<std::unique_ptr<CompositorFloatKeyframe>>;
+    Keyframes keyframesForTesting() const;
+
+    PassRefPtr<TimingFunction> getTimingFunctionForTesting() const;
+
 private:
     CompositorFloatAnimationCurve();
     CompositorFloatAnimationCurve(std::unique_ptr<cc::KeyframedFloatAnimationCurve>);
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp
index 7cb88f5..88d2c50 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatAnimationCurveTest.cpp
@@ -19,7 +19,7 @@
 TEST(WebFloatAnimationCurveTest, OneFloatKeyframe)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 2, *LinearTimingFunction::shared()));
     EXPECT_FLOAT_EQ(2, curve->getValue(-1));
     EXPECT_FLOAT_EQ(2, curve->getValue(0));
     EXPECT_FLOAT_EQ(2, curve->getValue(0.5));
@@ -31,8 +31,8 @@
 TEST(WebFloatAnimationCurveTest, TwoFloatKeyframe)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 2, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared()));
     EXPECT_FLOAT_EQ(2, curve->getValue(-1));
     EXPECT_FLOAT_EQ(2, curve->getValue(0));
     EXPECT_FLOAT_EQ(3, curve->getValue(0.5));
@@ -44,9 +44,9 @@
 TEST(WebFloatAnimationCurveTest, ThreeFloatKeyframe)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(2, 8), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 2, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(2, 8, *LinearTimingFunction::shared()));
     EXPECT_FLOAT_EQ(2, curve->getValue(-1));
     EXPECT_FLOAT_EQ(2, curve->getValue(0));
     EXPECT_FLOAT_EQ(3, curve->getValue(0.5));
@@ -60,10 +60,10 @@
 TEST(WebFloatAnimationCurveTest, RepeatedFloatKeyTimes)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 4), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 6), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(2, 6), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 4, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 6, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(2, 6, *LinearTimingFunction::shared()));
 
     EXPECT_FLOAT_EQ(4, curve->getValue(-1));
     EXPECT_FLOAT_EQ(4, curve->getValue(0));
@@ -82,9 +82,9 @@
 TEST(WebFloatAnimationCurveTest, UnsortedKeyframes)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(2, 8), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(0, 2), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 4), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(2, 8, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(0, 2, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 4, *LinearTimingFunction::shared()));
 
     EXPECT_FLOAT_EQ(2, curve->getValue(-1));
     EXPECT_FLOAT_EQ(2, curve->getValue(0));
@@ -100,8 +100,8 @@
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
     RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(0.25, 0, 0.75, 1);
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *cubic);
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *cubic));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     EXPECT_FLOAT_EQ(0, curve->getValue(0));
     EXPECT_LT(0, curve->getValue(0.25));
@@ -116,8 +116,8 @@
 TEST(WebFloatAnimationCurveTest, EaseTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE));
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE));
@@ -131,8 +131,8 @@
 TEST(WebFloatAnimationCurveTest, LinearTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *LinearTimingFunction::shared());
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *LinearTimingFunction::shared()));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     for (int i = 0; i <= 4; ++i) {
         const double time = i * 0.25;
@@ -144,8 +144,8 @@
 TEST(WebFloatAnimationCurveTest, EaseInTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN));
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN)));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_IN));
@@ -159,8 +159,8 @@
 TEST(WebFloatAnimationCurveTest, EaseOutTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_OUT));
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_OUT)));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_OUT));
@@ -174,8 +174,8 @@
 TEST(WebFloatAnimationCurveTest, EaseInOutTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT));
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT)));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE_IN_OUT));
@@ -194,8 +194,8 @@
     double x2 = 0.8;
     double y2 = 0.7;
     RefPtr<CubicBezierTimingFunction> cubic = CubicBezierTimingFunction::create(x1, y1, x2, y2);
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *cubic);
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *cubic));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::Create(x1, y1, x2, y2));
@@ -209,8 +209,8 @@
 TEST(WebFloatAnimationCurveTest, DefaultTimingFunction)
 {
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0, 0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE));
-    curve->addKeyframe(CompositorFloatKeyframe(1, 1), *LinearTimingFunction::shared());
+    curve->addKeyframe(CompositorFloatKeyframe(0, 0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)));
+    curve->addKeyframe(CompositorFloatKeyframe(1, 1, *LinearTimingFunction::shared()));
 
     std::unique_ptr<cc::TimingFunction> timingFunction(
         cc::CubicBezierTimingFunction::CreatePreset(CubicBezierTimingFunction::EaseType::EASE));
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp
new file mode 100644
index 0000000..42eb200
--- /dev/null
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.cpp
@@ -0,0 +1,40 @@
+// 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 "platform/animation/CompositorFloatKeyframe.h"
+
+#include "platform/animation/TimingFunction.h"
+
+namespace blink {
+
+CompositorFloatKeyframe::CompositorFloatKeyframe(double time, float value, const TimingFunction& timingFunction)
+    : m_floatKeyframe(cc::FloatKeyframe::Create(base::TimeDelta::FromSecondsD(time), value, timingFunction.cloneToCC()))
+{
+}
+
+CompositorFloatKeyframe::CompositorFloatKeyframe(std::unique_ptr<cc::FloatKeyframe> floatKeyframe)
+    : m_floatKeyframe(std::move(floatKeyframe))
+{
+}
+
+CompositorFloatKeyframe::~CompositorFloatKeyframe()
+{
+}
+
+double CompositorFloatKeyframe::time() const
+{
+    return m_floatKeyframe->Time().InSecondsF();
+}
+
+const cc::TimingFunction* CompositorFloatKeyframe::ccTimingFunction() const
+{
+    return m_floatKeyframe->timing_function();
+}
+
+std::unique_ptr<cc::FloatKeyframe> CompositorFloatKeyframe::cloneToCC() const
+{
+    return m_floatKeyframe->Clone();
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.h b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.h
index 6d22d29..24ddf71 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorFloatKeyframe.h
@@ -5,17 +5,31 @@
 #ifndef CompositorFloatKeyframe_h
 #define CompositorFloatKeyframe_h
 
+#include "cc/animation/keyframed_animation_curve.h"
+#include "platform/PlatformExport.h"
+#include "platform/animation/CompositorKeyframe.h"
+#include "wtf/Noncopyable.h"
+
 namespace blink {
 
-struct CompositorFloatKeyframe {
-    CompositorFloatKeyframe(double time, float value)
-        : time(time)
-        , value(value)
-    {
-    }
+class TimingFunction;
 
-    double time;
-    float value;
+class PLATFORM_EXPORT CompositorFloatKeyframe : public CompositorKeyframe {
+    WTF_MAKE_NONCOPYABLE(CompositorFloatKeyframe);
+public:
+    CompositorFloatKeyframe(double time, float value, const TimingFunction&);
+    CompositorFloatKeyframe(std::unique_ptr<cc::FloatKeyframe>);
+    ~CompositorFloatKeyframe() override;
+
+    // CompositorKeyframe implementation.
+    double time() const override;
+    const cc::TimingFunction* ccTimingFunction() const override;
+
+    float value() { return m_floatKeyframe->Value(); }
+    std::unique_ptr<cc::FloatKeyframe> cloneToCC() const;
+
+private:
+    std::unique_ptr<cc::FloatKeyframe> m_floatKeyframe;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.cpp
new file mode 100644
index 0000000..e22613e
--- /dev/null
+++ b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.cpp
@@ -0,0 +1,16 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/animation/CompositorKeyframe.h"
+
+#include "platform/animation/TimingFunction.h"
+
+namespace blink {
+
+PassRefPtr<TimingFunction> CompositorKeyframe::getTimingFunctionForTesting() const
+{
+    return createCompositorTimingFunctionFromCC(ccTimingFunction());
+}
+
+} // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.h
new file mode 100644
index 0000000..fc8ed52
--- /dev/null
+++ b/third_party/WebKit/Source/platform/animation/CompositorKeyframe.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 CompositorKeyframe_h
+#define CompositorKeyframe_h
+
+#include "platform/PlatformExport.h"
+#include "wtf/PassRefPtr.h"
+
+namespace cc {
+class TimingFunction;
+}
+
+namespace blink {
+
+class TimingFunction;
+
+class PLATFORM_EXPORT CompositorKeyframe {
+public:
+    virtual ~CompositorKeyframe() {}
+
+    virtual double time() const = 0;
+
+    PassRefPtr<TimingFunction> getTimingFunctionForTesting() const;
+
+private:
+    virtual const cc::TimingFunction* ccTimingFunction() const = 0;
+};
+
+} // namespace blink
+
+#endif // CompositorKeyframe_h
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
index 722f4be..de26f28 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.cpp
@@ -20,12 +20,9 @@
 {
 }
 
-void CompositorTransformAnimationCurve::addKeyframe(const CompositorTransformKeyframe& keyframe, const TimingFunction& timingFunction)
+void CompositorTransformAnimationCurve::addKeyframe(const CompositorTransformKeyframe& keyframe)
 {
-    const cc::TransformOperations& transformOperations = keyframe.value().asTransformOperations();
-    m_curve->AddKeyframe(cc::TransformKeyframe::Create(
-        base::TimeDelta::FromSecondsD(keyframe.time()), transformOperations,
-        timingFunction.cloneToCC()));
+    m_curve->AddKeyframe(keyframe.cloneToCC());
 }
 
 void CompositorTransformAnimationCurve::setTimingFunction(const TimingFunction& timingFunction)
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h
index ac63cd0..528fd29 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformAnimationCurve.h
@@ -34,7 +34,7 @@
 
     ~CompositorTransformAnimationCurve() override;
 
-    void addKeyframe(const CompositorTransformKeyframe&, const TimingFunction&);
+    void addKeyframe(const CompositorTransformKeyframe&);
     void setTimingFunction(const TimingFunction&);
 
     // CompositorAnimationCurve implementation.
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
index 0bcc1d2..cc0656b 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.cpp
@@ -8,25 +8,28 @@
 
 namespace blink {
 
-CompositorTransformKeyframe::CompositorTransformKeyframe(double time, std::unique_ptr<CompositorTransformOperations> value)
-    : m_time(time)
-    , m_value(std::move(value))
+CompositorTransformKeyframe::CompositorTransformKeyframe(double time, const CompositorTransformOperations& value, const TimingFunction& timingFunction)
+    : m_transformKeyframe(cc::TransformKeyframe::Create(base::TimeDelta::FromSecondsD(time), value.asTransformOperations(), timingFunction.cloneToCC()))
 {
 }
 
 CompositorTransformKeyframe::~CompositorTransformKeyframe()
 {
-    m_value.reset();
 }
 
 double CompositorTransformKeyframe::time() const
 {
-    return m_time;
+    return m_transformKeyframe->Time().InSecondsF();
 }
 
-const CompositorTransformOperations& CompositorTransformKeyframe::value() const
+const cc::TimingFunction* CompositorTransformKeyframe::ccTimingFunction() const
 {
-    return *m_value.get();
+    return m_transformKeyframe->timing_function();
+}
+
+std::unique_ptr<cc::TransformKeyframe> CompositorTransformKeyframe::cloneToCC() const
+{
+    return m_transformKeyframe->Clone();
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.h b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.h
index 1eeecd6..c8f339f 100644
--- a/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.h
+++ b/third_party/WebKit/Source/platform/animation/CompositorTransformKeyframe.h
@@ -5,25 +5,29 @@
 #ifndef CompositorTransformKeyframe_h
 #define CompositorTransformKeyframe_h
 
+#include "cc/animation/keyframed_animation_curve.h"
 #include "platform/PlatformExport.h"
+#include "platform/animation/CompositorKeyframe.h"
 #include "platform/animation/CompositorTransformOperations.h"
+#include "platform/animation/TimingFunction.h"
 #include "wtf/Noncopyable.h"
-#include <memory>
 
 namespace blink {
 
-class PLATFORM_EXPORT CompositorTransformKeyframe {
+class PLATFORM_EXPORT CompositorTransformKeyframe : public CompositorKeyframe {
     WTF_MAKE_NONCOPYABLE(CompositorTransformKeyframe);
 public:
-    CompositorTransformKeyframe(double time, std::unique_ptr<CompositorTransformOperations> value);
+    CompositorTransformKeyframe(double time, const CompositorTransformOperations& value, const TimingFunction&);
     ~CompositorTransformKeyframe();
 
-    double time() const;
-    const CompositorTransformOperations& value() const;
+    std::unique_ptr<cc::TransformKeyframe> cloneToCC() const;
+
+    // CompositorKeyframe implementation.
+    double time() const override;
+    const cc::TimingFunction* ccTimingFunction() const override;
 
 private:
-    double m_time;
-    std::unique_ptr<CompositorTransformOperations> m_value;
+    std::unique_ptr<cc::TransformKeyframe> m_transformKeyframe;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/platform/animation/TimingFunction.cpp b/third_party/WebKit/Source/platform/animation/TimingFunction.cpp
index c13b4ed..aea7cda 100644
--- a/third_party/WebKit/Source/platform/animation/TimingFunction.cpp
+++ b/third_party/WebKit/Source/platform/animation/TimingFunction.cpp
@@ -121,6 +121,33 @@
 }
 
 
+PassRefPtr<TimingFunction> createCompositorTimingFunctionFromCC(const cc::TimingFunction* timingFunction)
+{
+    if (!timingFunction)
+        return LinearTimingFunction::shared();
+
+    switch (timingFunction->GetType()) {
+    case cc::TimingFunction::Type::CUBIC_BEZIER: {
+        auto cubicTimingFunction = static_cast<const cc::CubicBezierTimingFunction*>(timingFunction);
+        if (cubicTimingFunction->ease_type() != cc::CubicBezierTimingFunction::EaseType::CUSTOM)
+            return CubicBezierTimingFunction::preset(cubicTimingFunction->ease_type());
+
+        const auto& bezier = cubicTimingFunction->bezier();
+        return CubicBezierTimingFunction::create(bezier.GetX1(), bezier.GetY1(), bezier.GetX2(), bezier.GetY2());
+    }
+
+    case cc::TimingFunction::Type::STEPS: {
+        auto stepsTimingFunction = static_cast<const cc::StepsTimingFunction*>(timingFunction);
+        return StepsTimingFunction::create(stepsTimingFunction->steps(), stepsTimingFunction->step_position());
+    }
+
+    default:
+        NOTREACHED();
+        return nullptr;
+    }
+}
+
+
 // Equals operators
 bool operator==(const LinearTimingFunction& lhs, const TimingFunction& rhs)
 {
diff --git a/third_party/WebKit/Source/platform/animation/TimingFunction.h b/third_party/WebKit/Source/platform/animation/TimingFunction.h
index c792adb0..386abd59 100644
--- a/third_party/WebKit/Source/platform/animation/TimingFunction.h
+++ b/third_party/WebKit/Source/platform/animation/TimingFunction.h
@@ -212,6 +212,8 @@
     std::unique_ptr<cc::StepsTimingFunction> m_steps;
 };
 
+PLATFORM_EXPORT PassRefPtr<TimingFunction> createCompositorTimingFunctionFromCC(const cc::TimingFunction*);
+
 PLATFORM_EXPORT bool operator==(const LinearTimingFunction&, const TimingFunction&);
 PLATFORM_EXPORT bool operator==(const CubicBezierTimingFunction&, const TimingFunction&);
 PLATFORM_EXPORT bool operator==(const StepsTimingFunction&, const TimingFunction&);
diff --git a/third_party/WebKit/Source/platform/blink_platform.gypi b/third_party/WebKit/Source/platform/blink_platform.gypi
index 7f4084b..d619bfd 100644
--- a/third_party/WebKit/Source/platform/blink_platform.gypi
+++ b/third_party/WebKit/Source/platform/blink_platform.gypi
@@ -165,7 +165,10 @@
       'animation/CompositorFilterKeyframe.h',
       'animation/CompositorFloatAnimationCurve.cpp',
       'animation/CompositorFloatAnimationCurve.h',
+      'animation/CompositorFloatKeyframe.cpp',
       'animation/CompositorFloatKeyframe.h',
+      'animation/CompositorKeyframe.cpp',
+      'animation/CompositorKeyframe.h',
       'animation/CompositorScrollOffsetAnimationCurve.cpp',
       'animation/CompositorScrollOffsetAnimationCurve.h',
       'animation/CompositorTargetProperty.h',
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
index f17cef0..76e307f5 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayerTest.cpp
@@ -108,7 +108,7 @@
     ASSERT_FALSE(m_platformLayer->hasActiveAnimationForTesting());
 
     std::unique_ptr<CompositorFloatAnimationCurve> curve = CompositorFloatAnimationCurve::create();
-    curve->addKeyframe(CompositorFloatKeyframe(0.0, 0.0), *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE));
+    curve->addKeyframe(CompositorFloatKeyframe(0.0, 0.0, *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE)));
     std::unique_ptr<CompositorAnimation> floatAnimation(CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0));
     int animationId = floatAnimation->id();
 
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
index 041f80e..fa8f552d 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -313,13 +313,13 @@
 
     const auto& timingFunction = *CubicBezierTimingFunction::preset(CubicBezierTimingFunction::EaseType::EASE);
 
-    curve->addKeyframe(CompositorFloatKeyframe(0, startOpacity), timingFunction);
+    curve->addKeyframe(CompositorFloatKeyframe(0, startOpacity, timingFunction));
     // Make sure we have displayed for at least minPreFadeDuration before starting to fade out.
     float extraDurationRequired = std::max(0.f, minPreFadeDuration - static_cast<float>(monotonicallyIncreasingTime() - m_startTime));
     if (extraDurationRequired)
-        curve->addKeyframe(CompositorFloatKeyframe(extraDurationRequired, startOpacity), timingFunction);
+        curve->addKeyframe(CompositorFloatKeyframe(extraDurationRequired, startOpacity, timingFunction));
     // For layout tests we don't fade out.
-    curve->addKeyframe(CompositorFloatKeyframe(fadeDuration + extraDurationRequired, layoutTestMode() ? startOpacity : 0), timingFunction);
+    curve->addKeyframe(CompositorFloatKeyframe(fadeDuration + extraDurationRequired, layoutTestMode() ? startOpacity : 0, timingFunction));
 
     std::unique_ptr<CompositorAnimation> animation = CompositorAnimation::create(*curve, CompositorTargetProperty::OPACITY, 0, 0);
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
index 28d7b0bd..9cbf72f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/common/checkout/scm/git.py
@@ -300,7 +300,7 @@
 
     def git_commit_detail(self, commit, log_format=None):
         args = ['log', '-1', commit]
-        if log_format:
+        if format:
             args.append('--format=' + log_format)
         return self._run_git(args)
 
diff --git a/tools/clang/translation_unit/TranslationUnitGenerator.cpp b/tools/clang/translation_unit/TranslationUnitGenerator.cpp
index 3590b0c..4d7524d9 100644
--- a/tools/clang/translation_unit/TranslationUnitGenerator.cpp
+++ b/tools/clang/translation_unit/TranslationUnitGenerator.cpp
@@ -31,6 +31,7 @@
 #include "clang/Tooling/Refactoring.h"
 #include "clang/Tooling/Tooling.h"
 #include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
 
 using clang::HeaderSearchOptions;
 using clang::tooling::CommonOptionsParser;
diff --git a/tools/metrics/histograms/find_unmapped_histograms.py b/tools/metrics/histograms/find_unmapped_histograms.py
index e25f52ae..95f5d970 100644
--- a/tools/metrics/histograms/find_unmapped_histograms.py
+++ b/tools/metrics/histograms/find_unmapped_histograms.py
@@ -24,6 +24,16 @@
 import extract_histograms
 
 
+C_FILENAME = re.compile(r"""
+    .*              # Anything
+    \.(cc|cpp|h|mm) # Ending in these extensions
+    $               # End of string
+    """, re.VERBOSE)
+TEST_FILENAME = re.compile(r"""
+    .*   # Anything
+    test # The word test
+    \.   # A literal '.'
+    """, re.VERBOSE)
 CPP_COMMENT = re.compile(r"""
     \s*             # Optional whitespace
     (?:             # Non-capturing group
@@ -185,7 +195,9 @@
   #   'path/to/foo.cc:420:  UMA_HISTOGRAM_COUNTS_100("FooGroup.FooName",'
   #   'path/to/bar.cc:632:  UMA_HISTOGRAM_ENUMERATION('
   locations = RunGit(['gs', 'UMA_HISTOGRAM']).split('\n')
-  filenames = set([location.split(':')[0] for location in locations])
+  all_filenames = set(location.split(':')[0] for location in locations);
+  filenames = [f for f in all_filenames
+               if C_FILENAME.match(f) and not TEST_FILENAME.match(f)]
 
   histograms = set()
   location_map = dict()
diff --git a/ui/app_list/presenter/app_list_presenter_impl.cc b/ui/app_list/presenter/app_list_presenter_impl.cc
index cd181d1..572528b 100644
--- a/ui/app_list/presenter/app_list_presenter_impl.cc
+++ b/ui/app_list/presenter/app_list_presenter_impl.cc
@@ -80,14 +80,12 @@
 
   is_visible_ = false;
 
-  // The dismissal may have occurred in response to the app list losing
-  // activation. Otherwise, our widget is currently active. When the animation
-  // completes we'll hide the widget, changing activation. If a menu is shown
-  // before the animation completes then the activation change triggers the menu
-  // to close. By deactivating now we ensure there is no activation change when
-  // the animation completes and any menus stay open.
-  if (view_->GetWidget()->IsActive())
-    view_->GetWidget()->Deactivate();
+  // Our widget is currently active. When the animation completes we'll hide
+  // the widget, changing activation. If a menu is shown before the animation
+  // completes then the activation change triggers the menu to close. By
+  // deactivating now we ensure there is no activation change when the
+  // animation completes and any menus stay open.
+  view_->GetWidget()->Deactivate();
 
   presenter_delegate_->OnDismissed();
   ScheduleAnimation();
diff --git a/ui/file_manager/file_manager/background/js/test_util_base.js b/ui/file_manager/file_manager/background/js/test_util_base.js
index 2bcb3af..c10a0f2d 100644
--- a/ui/file_manager/file_manager/background/js/test_util_base.js
+++ b/ui/file_manager/file_manager/background/js/test_util_base.js
@@ -26,6 +26,7 @@
   }
   var styles = {};
   var styleNames = opt_styleNames || [];
+  assert(Array.isArray(styleNames));
   var computedStyles = contentWindow.getComputedStyle(element);
   for (var i = 0; i < styleNames.length; i++) {
     styles[styleNames[i]] = computedStyles[styleNames[i]];
@@ -223,32 +224,79 @@
 /**
  * Queries all elements.
  *
- * @param {Window} contentWindow Window to be tested.
+ * @param {!Window} contentWindow Window to be tested.
  * @param {string} targetQuery Query to specify the element.
  * @param {?string} iframeQuery Iframe selector or null if no iframe.
  * @param {Array<string>=} opt_styleNames List of CSS property name to be
  *     obtained.
- * @return {Array<{attributes:Object<string>, text:string,
+ * @return {!Array<{attributes:Object<string>, text:string,
  *                  styles:Object<string>, hidden:boolean}>} Element
  *     information that contains contentText, attribute names and
  *     values, hidden attribute, and style names and values.
  */
 test.util.sync.queryAllElements = function(
     contentWindow, targetQuery, iframeQuery, opt_styleNames) {
+  return test.util.sync.deepQueryAllElements(
+      contentWindow, [targetQuery], iframeQuery, opt_styleNames);
+};
+
+/**
+ * Queries elements inside shadow DOM.
+ *
+ * @param {!Window} contentWindow Window to be tested.
+ * @param {!Array<string>} targetQuery Query to specify the element.
+ *   |targetQuery[0]| specifies the first element(s). |targetQuery[1]| specifies
+ *   elements inside the shadow DOM of the first element, and so on.
+ * @param {?string} iframeQuery Iframe selector or null if no iframe.
+ * @param {Array<string>=} opt_styleNames List of CSS property name to be
+ *     obtained.
+ * @return {!Array<{attributes:Object<string>, text:string,
+ *                  styles:Object<string>, hidden:boolean}>} Element
+ *     information that contains contentText, attribute names and
+ *     values, hidden attribute, and style names and values.
+ */
+test.util.sync.deepQueryAllElements = function(
+    contentWindow, targetQuery, iframeQuery, opt_styleNames) {
   var doc = test.util.sync.getDocument_(
       contentWindow, iframeQuery || undefined);
   if (!doc)
     return [];
-  // The return value of querySelectorAll is not an array.
-  return Array.prototype.map.call(
-      doc.querySelectorAll(targetQuery),
-      function(element) {
-        return extractElementInfo(element, contentWindow, opt_styleNames);
-      });
+
+  var elems = test.util.sync.deepQuerySelectorAll_(doc, targetQuery);
+  return elems.map(function(element) {
+    return extractElementInfo(element, contentWindow, opt_styleNames);
+  });
 };
 
 /**
- * Get the information of the active element.
+ * Selects elements below |root|, possibly following shadow DOM subtree.
+ *
+ * @param {(!HTMLElement|!Document)} root Element to search from.
+ * @param {!Array<string>} targetQuery Query to specify the element.
+ *   |targetQuery[0]| specifies the first element(s). |targetQuery[1]| specifies
+ *   elements inside the shadow DOM of the first element, and so on.
+ * @return {!Array<!HTMLElement>} Matched elements.
+ *
+ * @private
+ */
+test.util.sync.deepQuerySelectorAll_ = function(root, targetQuery) {
+  var elems = Array.prototype.slice.call(root.querySelectorAll(targetQuery[0]));
+  var remaining = targetQuery.slice(1);
+  if (remaining.length === 0)
+    return elems;
+
+  var res = [];
+  for (var i = 0; i < elems.length; i++) {
+    if (elems[i].shadowRoot) {
+      res = res.concat(
+          test.util.sync.deepQuerySelectorAll_(elems[i].shadowRoot, remaining));
+    }
+  }
+  return res;
+};
+
+/**
+ * Gets the information of the active element.
  *
  * @param {Window} contentWindow Window to be tested.
  * @param {string} targetQuery Query to specify the element.
diff --git a/ui/file_manager/integration_tests/file_manager/quick_view.js b/ui/file_manager/integration_tests/file_manager/quick_view.js
new file mode 100644
index 0000000..033d52d
--- /dev/null
+++ b/ui/file_manager/integration_tests/file_manager/quick_view.js
@@ -0,0 +1,56 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+'use strict';
+
+/**
+ * Tests opening the Quick View.
+ */
+testcase.openQuickView = function() {
+  var appId;
+
+  StepsRunner.run([
+    function() {
+      setupAndWaitUntilReady(null, RootPath.DOWNLOADS, this.next);
+    },
+    function(results) {
+      appId = results.windowId;
+      // Select an image file.
+      remoteCall.callRemoteTestUtil(
+          'selectFile', appId, ['My Desktop Background.png'], this.next);
+    },
+    function(results) {
+      chrome.test.assertTrue(results);
+      // Press Space key.
+      remoteCall.callRemoteTestUtil(
+          'fakeKeyDown', appId,
+          ['#file-list', ' ', ' ', false, false, false], this.next);
+    },
+    function(results) {
+      chrome.test.assertTrue(results);
+
+      // Wait until Quick View is displayed.
+      repeatUntil(function() {
+        return remoteCall
+            .callRemoteTestUtil(
+                'deepQueryAllElements', appId,
+                [['#quick-view', '#dialog'], null, ['display']])
+            .then(function(results) {
+              chrome.test.assertEq(1, results.length);
+              if (results[0].styles.display === 'none') {
+                return pending('Quick View is not opened yet.');
+              };
+              return results;
+            });
+      }).then(this.next);
+    },
+    function(results) {
+      chrome.test.assertEq(1, results.length);
+      // Check Quick View dialog is displayed.
+      chrome.test.assertEq('block', results[0].styles.display);
+
+      checkIfNoErrorsOccured(this.next);
+    },
+  ]);
+};
diff --git a/ui/file_manager/integration_tests/file_manager_test_manifest.json b/ui/file_manager/integration_tests/file_manager_test_manifest.json
index 4e979295..eec95004 100644
--- a/ui/file_manager/integration_tests/file_manager_test_manifest.json
+++ b/ui/file_manager/integration_tests/file_manager_test_manifest.json
@@ -28,6 +28,7 @@
       "file_manager/open_image_files.js",
       "file_manager/open_video_files.js",
       "file_manager/providers.js",
+      "file_manager/quick_view.js",
       "file_manager/restore_geometry.js",
       "file_manager/restore_prefs.js",
       "file_manager/share_dialog.js",
diff --git a/ui/file_manager/integration_tests/remote_call.js b/ui/file_manager/integration_tests/remote_call.js
index aa014c6..547e031 100644
--- a/ui/file_manager/integration_tests/remote_call.js
+++ b/ui/file_manager/integration_tests/remote_call.js
@@ -26,7 +26,8 @@
 };
 
 /**
- * Calls a remote test util in Files.app's extension. See: test_util.js.
+ * Calls a remote test util in Files.app's extension. See:
+ * registerRemoteTestUtils in test_util_base.js.
  *
  * @param {string} func Function name.
  * @param {?string} appId Target window's App ID or null for functions
@@ -59,10 +60,11 @@
             appId: appId,
             args: args
           },
+          {},
           function(var_args) {
             if (stepByStep) {
               console.info('Returned value:');
-              console.info(arguments);
+              console.info(JSON.stringify(arguments));
             }
             if (opt_callback)
               opt_callback.apply(null, arguments);