diff --git a/DEPS b/DEPS
index fd254dc..d7c6def 100644
--- a/DEPS
+++ b/DEPS
@@ -40,7 +40,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '6d9e4ee14e7eb9029ccf648a79af83db5f7125c4',
+  'skia_revision': 'e5ede4b138e84d05d63c9ab7f426884dc9b4d926',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -64,7 +64,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'cf7df1bfba955f48f1f70211e55dc0d5c87afcfe',
+  'pdfium_revision': '6f9b1d7eff38d503de231fc7260f012af774ce62',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling openmax_dl
   # and whatever else without interference from each other.
@@ -96,7 +96,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '29f450ae4dcb657197866e4d48bc465834b8d8c6',
+  'catapult_revision': '07a2febe723a491c9cfdd7f1617a61f2ebcb9186',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -1220,7 +1220,7 @@
       'action': [
         'python',
         'src/build/fuchsia/update_sdk.py',
-        'd9ccb5f3ba70118dba419f8202ebd74613005c9c',
+        'f319affb3cb0a9baa3cebe74ad33fa17f232f09c',
       ],
     },
   ],
diff --git a/android_webview/browser/hardware_renderer.cc b/android_webview/browser/hardware_renderer.cc
index 09cc2b3..43cd1f451 100644
--- a/android_webview/browser/hardware_renderer.cc
+++ b/android_webview/browser/hardware_renderer.cc
@@ -35,6 +35,10 @@
   DCHECK(last_egl_context_);
   surfaces_->GetFrameSinkManager()->surface_manager()->RegisterFrameSinkId(
       frame_sink_id_);
+#if DCHECK_IS_ON()
+  surfaces_->GetFrameSinkManager()->surface_manager()->SetFrameSinkDebugLabel(
+      frame_sink_id_, "HardwareRenderer");
+#endif
   CreateNewCompositorFrameSinkSupport();
 }
 
diff --git a/ash/mus/non_client_frame_controller_unittest.cc b/ash/mus/non_client_frame_controller_unittest.cc
index 9222a6b..972ad497 100644
--- a/ash/mus/non_client_frame_controller_unittest.cc
+++ b/ash/mus/non_client_frame_controller_unittest.cc
@@ -26,7 +26,7 @@
 
 namespace {
 
-gfx::Rect GetQuadBoundsInScreen(const cc::DrawQuad* quad) {
+gfx::Rect GetQuadBoundsInScreen(const viz::DrawQuad* quad) {
   return cc::MathUtil::MapEnclosingClippedRect(
       quad->shared_quad_state->quad_to_target_transform, quad->visible_rect);
 }
@@ -48,7 +48,7 @@
   DCHECK_EQ(1u, frame.render_pass_list.size());
   const cc::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
   for (const auto* quad : quad_list) {
-    if (quad->material != cc::DrawQuad::Material::SOLID_COLOR)
+    if (quad->material != viz::DrawQuad::Material::SOLID_COLOR)
       continue;
 
     auto* color_quad = cc::SolidColorDrawQuad::MaterialCast(quad);
@@ -65,7 +65,7 @@
   DCHECK_EQ(1u, frame.render_pass_list.size());
   const cc::QuadList& quad_list = frame.render_pass_list[0]->quad_list;
   for (const auto* quad : quad_list) {
-    if (quad->material == cc::DrawQuad::Material::TILED_CONTENT &&
+    if (quad->material == viz::DrawQuad::Material::TILED_CONTENT &&
         GetQuadBoundsInScreen(quad) == screen_rect)
       return true;
   }
diff --git a/base/allocator/partition_allocator/page_allocator.h b/base/allocator/partition_allocator/page_allocator.h
index a16eaadf..b47ddb9 100644
--- a/base/allocator/partition_allocator/page_allocator.h
+++ b/base/allocator/partition_allocator/page_allocator.h
@@ -41,14 +41,18 @@
 };
 
 // Allocate one or more pages.
-// The requested address is just a hint; the actual address returned may
-// differ. The returned address will be aligned at least to align bytes.
-// length is in bytes, and must be a multiple of kPageAllocationGranularity.
-// align is in bytes, and must be a power-of-two multiple of
-// kPageAllocationGranularity.
-// If address is null, then a suitable and randomized address will be chosen
+//
+// The requested |address| is just a hint; the actual address returned may
+// differ. The returned address will be aligned at least to |align| bytes.
+// |length| is in bytes, and must be a multiple of |kPageAllocationGranularity|.
+// |align| is in bytes, and must be a power-of-two multiple of
+// |kPageAllocationGranularity|.
+//
+// If |address| is null, then a suitable and randomized address will be chosen
 // automatically.
-// page_accessibility controls the permission of the allocated pages.
+//
+// |page_accessibility| controls the permission of the allocated pages.
+//
 // This call will return null if the allocation cannot be satisfied.
 BASE_EXPORT void* AllocPages(void* address,
                              size_t length,
@@ -56,59 +60,74 @@
                              PageAccessibilityConfiguration page_accessibility,
                              bool commit = true);
 
-// Free one or more pages.
-// address and length must match a previous call to allocPages().
+// Free one or more pages starting at |address| and continuing for |length|
+// bytes.
+//
+// |address| and |length| must match a previous call to |AllocPages|. Therefore,
+// |address| must be aligned to |kPageAllocationGranularity| bytes, and |length|
+// must be a multiple of |kPageAllocationGranularity|.
 BASE_EXPORT void FreePages(void* address, size_t length);
 
-// Mark one or more system pages with the given access.
-// length must be a multiple of kSystemPageSize bytes.
-// The result bool value indicates whether the permission change succeeded or
-// not. You must check the result (in most cases you need to CHECK that it is
-// true).
+// Mark one or more system pages, starting at |address| with the given
+// |page_accessibility|. |length| must be a multiple of |kSystemPageSize| bytes.
+//
+// Returns true if the permission change succeeded. In most cases you must
+// |CHECK| the result.
 BASE_EXPORT WARN_UNUSED_RESULT bool SetSystemPagesAccess(
     void* address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility);
 
-// Decommit one or more system pages. Decommitted means that the physical memory
-// is released to the system, but the virtual address space remains reserved.
-// System pages are re-committed by calling RecommitSystemPages(). Touching
-// a decommitted page _may_ fault.
+// Decommit one or more system pages starting at |address| and continuing for
+// |length| bytes. |length| must be a multiple of |kSystemPageSize|.
+//
+// Decommitted means that the physical memory is released to the system, but the
+// virtual address space remains reserved. System pages are re-committed by
+// calling |RecommitSystemPages|. Touching a decommitted page _may_ fault.
+//
 // Clients should not make any assumptions about the contents of decommitted
 // system pages, before or after they write to the page. The only guarantee
 // provided is that the contents of the system page will be deterministic again
 // after recommitting and writing to it. In particlar note that system pages are
-// not guaranteed to be zero-filled upon re-commit. length must be a multiple of
-// kSystemPageSize bytes.
+// not guaranteed to be zero-filled upon re-commit.
 BASE_EXPORT void DecommitSystemPages(void* address, size_t length);
 
-// Recommit one or more system pages with the given access. Decommitted system
-// pages must be recommitted with their original permissions before they are
-// used again. Note that this operation may be a no-op on some platforms.
-// length must be a multiple of kSystemPageSize bytes.
-// The result bool value indicates whether the recommit succeeded or
-// not. You must check the result (in most cases you need to CHECK that it is
-// true).
+// Recommit one or more system pages, starting at |address| and continuing for
+// |length| bytes with the given |page_accessibility|. |length| must be a
+// multiple of |kSystemPageSize|.
+//
+// Decommitted system pages must be recommitted with their original permissions
+// before they are used again. Note that this operation may be a no-op on some
+// platforms.
+//
+// Returns true if the recommit change succeeded. In most cases you must |CHECK|
+// the result.
 BASE_EXPORT WARN_UNUSED_RESULT bool RecommitSystemPages(
     void* address,
     size_t length,
     PageAccessibilityConfiguration page_accessibility);
 
-// Discard one or more system pages. Discarding is a hint to the system that
-// the page is no longer required. The hint may:
-// - Do nothing.
-// - Discard the page immediately, freeing up physical pages.
-// - Discard the page at some time in the future in response to memory pressure.
-// Only committed pages should be discarded. Discarding a page does not
-// decommit it, and it is valid to discard an already-discarded page.
-// A read or write to a discarded page will not fault.
-// Reading from a discarded page may return the original page content, or a
-// page full of zeroes.
+// Discard one or more system pages starting at |address| and continuing for
+// |length| bytes. |length| must be a multiple of |kSystemPageSize|.
+//
+// Discarding is a hint to the system that the page is no longer required. The
+// hint may:
+//   - Do nothing.
+//   - Discard the page immediately, freeing up physical pages.
+//   - Discard the page at some time in the future in response to memory
+//   pressure.
+//
+// Only committed pages should be discarded. Discarding a page does not decommit
+// it, and it is valid to discard an already-discarded page. A read or write to
+// a discarded page will not fault.
+//
+// Reading from a discarded page may return the original page content, or a page
+// full of zeroes.
+//
 // Writing to a discarded page is the only guaranteed way to tell the system
 // that the page is required again. Once written to, the content of the page is
 // guaranteed stable once more. After being written to, the page content may be
 // based on the original page content, or a page of zeroes.
-// length must be a multiple of kSystemPageSize bytes.
 BASE_EXPORT void DiscardSystemPages(void* address, size_t length);
 
 ALWAYS_INLINE uintptr_t RoundUpToSystemPage(uintptr_t address) {
@@ -119,17 +138,18 @@
   return address & kSystemPageBaseMask;
 }
 
-// Reserves address space equal to 'size' bytes, aligned to
-// kPageAllocationGranularity. This can be called early on to make it more
+// Reserves (at least) |size| bytes of address space, aligned to
+// |kPageAllocationGranularity|. This can be called early on to make it more
 // likely that large allocations will succeed. Returns true if the reservation
 // succeeded, false if the reservation failed or a reservation was already made.
 BASE_EXPORT bool ReserveAddressSpace(size_t size);
 
-// Releases any reserved address space. AllocPages calls this automatically on
+// Releases any reserved address space. |AllocPages| calls this automatically on
 // an allocation failure. External allocators may also call this on failure.
 BASE_EXPORT void ReleaseReservation();
 
-// Returns errno (or GetLastError code) when mmap (or VirtualAlloc) fails.
+// Returns |errno| (POSIX) or the result of |GetLastError| (Windows) when |mmap|
+// (POSIX) or |VirtualAlloc| (Windows) fails.
 BASE_EXPORT uint32_t GetAllocPageErrorCode();
 
 }  // namespace base
diff --git a/cc/BUILD.gn b/cc/BUILD.gn
index d7e388b..9d9f592 100644
--- a/cc/BUILD.gn
+++ b/cc/BUILD.gn
@@ -185,8 +185,6 @@
     "quads/debug_border_draw_quad.h",
     "quads/draw_polygon.cc",
     "quads/draw_polygon.h",
-    "quads/draw_quad.cc",
-    "quads/draw_quad.h",
     "quads/largest_draw_quad.cc",
     "quads/largest_draw_quad.h",
     "quads/nine_patch_generator.cc",
@@ -649,7 +647,6 @@
     "input/scrollbar_animation_controller_unittest.cc",
     "input/single_scrollbar_animation_controller_thinning_unittest.cc",
     "ipc/cc_param_traits_unittest.cc",
-    "ipc/struct_traits_unittest.cc",
     "layers/effect_tree_layer_list_iterator_unittest.cc",
     "layers/heads_up_display_layer_impl_unittest.cc",
     "layers/heads_up_display_unittest.cc",
@@ -784,7 +781,6 @@
     ":test_support",
     "//base/test:test_support",
     "//cc/ipc",
-    "//cc/ipc:test_interfaces",
     "//cc/paint",
     "//components/viz/common",
     "//components/viz/service",
@@ -838,7 +834,6 @@
     "//base",
     "//base/test:test_support",
     "//cc/ipc",
-    "//cc/ipc:interfaces",
     "//cc/paint",
     "//components/viz/common",
     "//components/viz/test:test_support",
diff --git a/cc/animation/BUILD.gn b/cc/animation/BUILD.gn
index 7ae45962..4422a45 100644
--- a/cc/animation/BUILD.gn
+++ b/cc/animation/BUILD.gn
@@ -22,6 +22,8 @@
     "animation_player.cc",
     "animation_player.h",
     "animation_target.h",
+    "animation_ticker.cc",
+    "animation_ticker.h",
     "animation_timeline.cc",
     "animation_timeline.h",
     "element_animations.cc",
diff --git a/cc/animation/animation_player.cc b/cc/animation/animation_player.cc
index c480e8e..3f32fbac 100644
--- a/cc/animation/animation_player.cc
+++ b/cc/animation/animation_player.cc
@@ -12,6 +12,7 @@
 #include "cc/animation/animation_delegate.h"
 #include "cc/animation/animation_events.h"
 #include "cc/animation/animation_host.h"
+#include "cc/animation/animation_ticker.h"
 #include "cc/animation/animation_timeline.h"
 #include "cc/animation/scroll_offset_animation_curve.h"
 #include "cc/animation/transform_operations.h"
@@ -26,19 +27,15 @@
 AnimationPlayer::AnimationPlayer(int id)
     : animation_host_(),
       animation_timeline_(),
-      element_animations_(),
       animation_delegate_(),
       id_(id),
       needs_push_properties_(false),
-      needs_to_start_animations_(false),
-      is_ticking_(false),
-      scroll_offset_animation_was_interrupted_(false) {
+      animation_ticker_(new AnimationTicker(this)) {
   DCHECK(id_);
 }
 
 AnimationPlayer::~AnimationPlayer() {
   DCHECK(!animation_timeline_);
-  DCHECK(!element_animations_);
 }
 
 scoped_refptr<AnimationPlayer> AnimationPlayer::CreateImplInstance() const {
@@ -46,6 +43,10 @@
   return player;
 }
 
+ElementId AnimationPlayer::element_id() const {
+  return animation_ticker_->element_id();
+}
+
 void AnimationPlayer::SetAnimationHost(AnimationHost* animation_host) {
   animation_host_ = animation_host;
 }
@@ -56,21 +57,23 @@
 
   // We need to unregister player to manage ElementAnimations and observers
   // properly.
-  if (element_id_ && element_animations_)
+  if (animation_ticker_->has_attached_element() &&
+      animation_ticker_->has_bound_element_animations())
     UnregisterPlayer();
 
   animation_timeline_ = timeline;
 
   // Register player only if layer AND host attached.
-  if (element_id_ && animation_host_)
+  if (animation_ticker_->has_attached_element() && animation_host_)
     RegisterPlayer();
 }
 
-void AnimationPlayer::AttachElement(ElementId element_id) {
-  DCHECK(!element_id_);
-  DCHECK(element_id);
+scoped_refptr<ElementAnimations> AnimationPlayer::element_animations() const {
+  return animation_ticker_->element_animations();
+}
 
-  element_id_ = element_id;
+void AnimationPlayer::AttachElement(ElementId element_id) {
+  animation_ticker_->AttachElement(element_id);
 
   // Register player only if layer AND host attached.
   if (animation_host_)
@@ -78,165 +81,66 @@
 }
 
 void AnimationPlayer::DetachElement() {
-  DCHECK(element_id_);
+  DCHECK(animation_ticker_->has_attached_element());
 
   if (animation_host_)
     UnregisterPlayer();
 
-  element_id_ = ElementId();
+  animation_ticker_->DetachElement();
 }
 
 void AnimationPlayer::RegisterPlayer() {
-  DCHECK(element_id_);
   DCHECK(animation_host_);
-  DCHECK(!element_animations_);
+  DCHECK(animation_ticker_->has_attached_element());
+  DCHECK(!animation_ticker_->has_bound_element_animations());
 
   // Create ElementAnimations or re-use existing.
-  animation_host_->RegisterPlayerForElement(element_id_, this);
+  animation_host_->RegisterPlayerForElement(animation_ticker_->element_id(),
+                                            this);
   // Get local reference to shared ElementAnimations.
   BindElementAnimations();
 }
 
 void AnimationPlayer::UnregisterPlayer() {
-  DCHECK(element_id_);
   DCHECK(animation_host_);
-  DCHECK(element_animations_);
+  DCHECK(animation_ticker_->has_attached_element());
+  DCHECK(animation_ticker_->has_bound_element_animations());
 
   UnbindElementAnimations();
   // Destroy ElementAnimations or release it if it's still needed.
-  animation_host_->UnregisterPlayerForElement(element_id_, this);
+  animation_host_->UnregisterPlayerForElement(animation_ticker_->element_id(),
+                                              this);
 }
 
 void AnimationPlayer::BindElementAnimations() {
-  DCHECK(!element_animations_);
-  element_animations_ =
-      animation_host_->GetElementAnimationsForElementId(element_id_);
-  DCHECK(element_animations_);
-
-  if (!animations_.empty())
-    AnimationAdded();
-
+  animation_ticker_->BindElementAnimations(animation_host_);
   SetNeedsPushProperties();
 }
 
 void AnimationPlayer::UnbindElementAnimations() {
   SetNeedsPushProperties();
-  element_animations_ = nullptr;
+  animation_ticker_->UnbindElementAnimations();
 }
 
 void AnimationPlayer::AddAnimation(std::unique_ptr<Animation> animation) {
-  DCHECK(animation->target_property_id() != TargetProperty::SCROLL_OFFSET ||
-         (animation_host_ && animation_host_->SupportsScrollAnimations()));
-  DCHECK(!animation->is_impl_only() ||
-         animation->target_property_id() == TargetProperty::SCROLL_OFFSET);
-
-  animations_.push_back(std::move(animation));
-  if (element_animations_) {
-    AnimationAdded();
-    SetNeedsPushProperties();
-  }
-}
-
-void AnimationPlayer::AnimationAdded() {
-  DCHECK(element_animations_);
-
-  SetNeedsCommit();
-  needs_to_start_animations_ = true;
-
-  UpdateTickingState(UpdateTickingType::NORMAL);
-  element_animations_->UpdateClientAnimationState();
+  animation_ticker_->AddAnimation(std::move(animation));
 }
 
 void AnimationPlayer::PauseAnimation(int animation_id, double time_offset) {
-  const base::TimeDelta time_delta = base::TimeDelta::FromSecondsD(time_offset);
-
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->id() == animation_id) {
-      animations_[i]->SetRunState(Animation::PAUSED,
-                                  time_delta + animations_[i]->start_time() +
-                                      animations_[i]->time_offset());
-    }
-  }
-
-  if (element_animations_) {
-    SetNeedsCommit();
-    SetNeedsPushProperties();
-  }
+  animation_ticker_->PauseAnimation(animation_id, time_offset);
 }
 
 void AnimationPlayer::RemoveAnimation(int animation_id) {
-  bool animation_removed = false;
-
-  // Since we want to use the animations that we're going to remove, we need to
-  // use a stable_parition here instead of remove_if. Remove_if leaves the
-  // removed items in an unspecified state.
-  auto animations_to_remove = std::stable_partition(
-      animations_.begin(), animations_.end(),
-      [animation_id](const std::unique_ptr<Animation>& animation) {
-        return animation->id() != animation_id;
-      });
-  for (auto it = animations_to_remove; it != animations_.end(); ++it) {
-    if ((*it)->target_property_id() == TargetProperty::SCROLL_OFFSET) {
-      if (element_animations_)
-        scroll_offset_animation_was_interrupted_ = true;
-    } else if (!(*it)->is_finished()) {
-      animation_removed = true;
-    }
-  }
-
-  animations_.erase(animations_to_remove, animations_.end());
-
-  if (element_animations_) {
-    UpdateTickingState(UpdateTickingType::NORMAL);
-    if (animation_removed)
-      element_animations_->UpdateClientAnimationState();
-    SetNeedsCommit();
-    SetNeedsPushProperties();
-  }
+  animation_ticker_->RemoveAnimation(animation_id);
 }
 
 void AnimationPlayer::AbortAnimation(int animation_id) {
-  if (Animation* animation = GetAnimationById(animation_id)) {
-    if (!animation->is_finished()) {
-      animation->SetRunState(Animation::ABORTED, last_tick_time_);
-      if (element_animations_)
-        element_animations_->UpdateClientAnimationState();
-    }
-  }
-
-  if (element_animations_) {
-    SetNeedsCommit();
-    SetNeedsPushProperties();
-  }
+  animation_ticker_->AbortAnimation(animation_id);
 }
 
 void AnimationPlayer::AbortAnimations(TargetProperty::Type target_property,
                                       bool needs_completion) {
-  if (needs_completion)
-    DCHECK(target_property == TargetProperty::SCROLL_OFFSET);
-
-  bool aborted_animation = false;
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->target_property_id() == target_property &&
-        !animations_[i]->is_finished()) {
-      // Currently only impl-only scroll offset animations can be completed on
-      // the main thread.
-      if (needs_completion && animations_[i]->is_impl_only()) {
-        animations_[i]->SetRunState(Animation::ABORTED_BUT_NEEDS_COMPLETION,
-                                    last_tick_time_);
-      } else {
-        animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_);
-      }
-      aborted_animation = true;
-    }
-  }
-
-  if (element_animations_) {
-    if (aborted_animation)
-      element_animations_->UpdateClientAnimationState();
-    SetNeedsCommit();
-    SetNeedsPushProperties();
-  }
+  animation_ticker_->AbortAnimations(target_property, needs_completion);
 }
 
 void AnimationPlayer::PushPropertiesTo(AnimationPlayer* player_impl) {
@@ -245,24 +149,28 @@
   needs_push_properties_ = false;
 
   // Create or destroy ElementAnimations.
-  if (element_id_ != player_impl->element_id()) {
-    if (player_impl->element_id())
+  ElementId element_id = animation_ticker_->element_id();
+  AnimationTicker* animation_ticker_impl = player_impl->animation_ticker_.get();
+  if (element_id != animation_ticker_impl->element_id()) {
+    if (animation_ticker_impl->has_attached_element())
       player_impl->DetachElement();
-    if (element_id_)
-      player_impl->AttachElement(element_id_);
+    if (element_id)
+      player_impl->AttachElement(element_id);
   }
 
-  if (!has_any_animation() && !player_impl->has_any_animation())
+  if (!animation_ticker_->has_any_animation() &&
+      !animation_ticker_impl->has_any_animation())
     return;
 
-  MarkAbortedAnimationsForDeletion(player_impl);
-  PurgeAnimationsMarkedForDeletion(/* impl_only */ false);
-  PushNewAnimationsToImplThread(player_impl);
+  animation_ticker_->MarkAbortedAnimationsForDeletion(animation_ticker_impl);
+  animation_ticker_->PurgeAnimationsMarkedForDeletion(/* impl_only */ false);
+  animation_ticker_->PushNewAnimationsToImplThread(animation_ticker_impl);
 
   // Remove finished impl side animations only after pushing,
   // and only after the animations are deleted on the main thread
   // this insures we will never push an animation twice.
-  RemoveAnimationsCompletedOnMainThread(player_impl);
+  animation_ticker_->RemoveAnimationsCompletedOnMainThread(
+      animation_ticker_impl);
 
   PushPropertiesToImplThread(player_impl);
 
@@ -271,110 +179,54 @@
 
 void AnimationPlayer::Tick(base::TimeTicks monotonic_time) {
   DCHECK(!monotonic_time.is_null());
-  DCHECK(element_animations_);
-
-  if (!element_animations_->has_element_in_any_list())
-    return;
-
-  if (needs_to_start_animations())
-    StartAnimations(monotonic_time);
-
-  TickAnimations(monotonic_time);
-
-  last_tick_time_ = monotonic_time;
-  element_animations_->UpdateClientAnimationState();
+  animation_ticker_->Tick(monotonic_time);
 }
 
 void AnimationPlayer::UpdateState(bool start_ready_animations,
                                   AnimationEvents* events) {
-  DCHECK(element_animations_);
-  if (!element_animations_->has_element_in_active_list())
-    return;
-
-  // Animate hasn't been called, this happens if an element has been added
-  // between the Commit and Draw phases.
-  if (last_tick_time_ == base::TimeTicks())
-    return;
-
-  if (start_ready_animations)
-    PromoteStartedAnimations(last_tick_time_, events);
-
-  MarkFinishedAnimations(last_tick_time_);
-  MarkAnimationsForDeletion(last_tick_time_, events);
-  PurgeAnimationsMarkedForDeletion(/* impl_only */ true);
-
-  if (start_ready_animations) {
-    if (needs_to_start_animations()) {
-      StartAnimations(last_tick_time_);
-      PromoteStartedAnimations(last_tick_time_, events);
-    }
-  }
+  animation_ticker_->UpdateState(start_ready_animations, events);
 
   UpdateTickingState(UpdateTickingType::NORMAL);
 }
 
 void AnimationPlayer::UpdateTickingState(UpdateTickingType type) {
-  bool force = type == UpdateTickingType::FORCE;
-  if (animation_host_) {
-    bool was_ticking = is_ticking_;
-    is_ticking_ = HasNonDeletedAnimation();
+  animation_ticker_->UpdateTickingState(type);
+}
 
-    bool has_element_in_any_list =
-        element_animations_->has_element_in_any_list();
-
-    if (is_ticking_ && ((!was_ticking && has_element_in_any_list) || force)) {
-      animation_host_->AddToTicking(this);
-    } else if (!is_ticking_ && (was_ticking || force)) {
-      RemoveFromTicking();
-    }
-  }
+void AnimationPlayer::AddToTicking() {
+  DCHECK(animation_host_);
+  animation_host_->AddToTicking(this);
 }
 
 void AnimationPlayer::RemoveFromTicking() {
   DCHECK(animation_host_);
   // Resetting last_tick_time_ here ensures that calling ::UpdateState
   // before ::Animate doesn't start an animation.
-  is_ticking_ = false;
-  last_tick_time_ = base::TimeTicks();
+  animation_ticker_->RemoveFromTicking();
   animation_host_->RemoveFromTicking(this);
 }
 
 bool AnimationPlayer::NotifyAnimationStarted(const AnimationEvent& event) {
   DCHECK(!event.is_impl_only);
 
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->group() == event.group_id &&
-        animations_[i]->target_property_id() == event.target_property &&
-        animations_[i]->needs_synchronized_start_time()) {
-      animations_[i]->set_needs_synchronized_start_time(false);
-      if (!animations_[i]->has_set_start_time())
-        animations_[i]->set_start_time(event.monotonic_time);
-
-      if (animation_delegate_) {
-        animation_delegate_->NotifyAnimationStarted(
-            event.monotonic_time, event.target_property, event.group_id);
-      }
-      return true;
+  if (animation_ticker_->NotifyAnimationStarted(event)) {
+    if (animation_delegate_) {
+      animation_delegate_->NotifyAnimationStarted(
+          event.monotonic_time, event.target_property, event.group_id);
     }
+    return true;
   }
-
   return false;
 }
 
 bool AnimationPlayer::NotifyAnimationFinished(const AnimationEvent& event) {
   DCHECK(!event.is_impl_only);
-
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->group() == event.group_id &&
-        animations_[i]->target_property_id() == event.target_property) {
-      animations_[i]->set_received_finished_event(true);
-
-      if (animation_delegate_) {
-        animation_delegate_->NotifyAnimationFinished(
-            event.monotonic_time, event.target_property, event.group_id);
-      }
-      return true;
+  if (animation_ticker_->NotifyAnimationFinished(event)) {
+    if (animation_delegate_) {
+      animation_delegate_->NotifyAnimationFinished(
+          event.monotonic_time, event.target_property, event.group_id);
     }
+    return true;
   }
 
   // This is for the case when an animation is already removed on main thread,
@@ -387,27 +239,21 @@
 bool AnimationPlayer::NotifyAnimationFinishedForTesting(
     TargetProperty::Type target_property,
     int group_id) {
-  AnimationEvent event(AnimationEvent::FINISHED, element_id_, group_id,
+  AnimationEvent event(AnimationEvent::FINISHED,
+                       animation_ticker_->element_id(), group_id,
                        target_property, base::TimeTicks());
   return NotifyAnimationFinished(event);
 }
 
 bool AnimationPlayer::NotifyAnimationAborted(const AnimationEvent& event) {
   DCHECK(!event.is_impl_only);
-
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->group() == event.group_id &&
-        animations_[i]->target_property_id() == event.target_property) {
-      animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time);
-      animations_[i]->set_received_finished_event(true);
-      if (animation_delegate_) {
-        animation_delegate_->NotifyAnimationAborted(
-            event.monotonic_time, event.target_property, event.group_id);
-      }
-      return true;
+  if (animation_ticker_->NotifyAnimationAborted(event)) {
+    if (animation_delegate_) {
+      animation_delegate_->NotifyAnimationAborted(
+          event.monotonic_time, event.target_property, event.group_id);
     }
+    return true;
   }
-
   return false;
 }
 
@@ -427,6 +273,33 @@
   }
 }
 
+void AnimationPlayer::NotifyImplOnlyAnimationStarted(
+    AnimationEvent& started_event) {
+  if (animation_delegate_) {
+    animation_delegate_->NotifyAnimationStarted(started_event.monotonic_time,
+                                                started_event.target_property,
+                                                started_event.group_id);
+  }
+}
+
+void AnimationPlayer::NotifyImplOnlyAnimationFinished(
+    AnimationEvent& finished_event) {
+  if (animation_delegate_) {
+    animation_delegate_->NotifyAnimationFinished(finished_event.monotonic_time,
+                                                 finished_event.target_property,
+                                                 finished_event.group_id);
+  }
+}
+
+void AnimationPlayer::NotifyAnimationTakeoverByMain(
+    AnimationEvent& aborted_event) {
+  if (animation_delegate_) {
+    animation_delegate_->NotifyAnimationFinished(aborted_event.monotonic_time,
+                                                 aborted_event.target_property,
+                                                 aborted_event.group_id);
+  }
+}
+
 void AnimationPlayer::SetNeedsCommit() {
   DCHECK(animation_host_);
   animation_host_->SetNeedsCommit();
@@ -438,730 +311,86 @@
   DCHECK(animation_timeline_);
   animation_timeline_->SetNeedsPushProperties();
 
-  DCHECK(element_animations_);
-  element_animations_->SetNeedsPushProperties();
+  DCHECK(element_animations());
+  element_animations()->SetNeedsPushProperties();
 }
 
 bool AnimationPlayer::HasTickingAnimation() const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (!animations_[i]->is_finished())
-      return true;
-  }
-  return false;
+  return animation_ticker_->HasTickingAnimation();
 }
 
-bool AnimationPlayer::HasNonDeletedAnimation() const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION)
-      return true;
-  }
-
-  return false;
-}
-
-void AnimationPlayer::StartAnimations(base::TimeTicks monotonic_time) {
-  DCHECK(needs_to_start_animations_);
-  needs_to_start_animations_ = false;
-  // First collect running properties affecting each type of element.
-  TargetProperties blocked_properties_for_active_elements;
-  TargetProperties blocked_properties_for_pending_elements;
-  std::vector<size_t> animations_waiting_for_target;
-
-  animations_waiting_for_target.reserve(animations_.size());
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->run_state() == Animation::STARTING ||
-        animations_[i]->run_state() == Animation::RUNNING) {
-      int property = animations_[i]->target_property_id();
-      if (animations_[i]->affects_active_elements()) {
-        blocked_properties_for_active_elements[property] = true;
-      }
-      if (animations_[i]->affects_pending_elements()) {
-        blocked_properties_for_pending_elements[property] = true;
-      }
-    } else if (animations_[i]->run_state() ==
-               Animation::WAITING_FOR_TARGET_AVAILABILITY) {
-      animations_waiting_for_target.push_back(i);
-    }
-  }
-
-  for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) {
-    // Collect all properties for animations with the same group id (they
-    // should all also be in the list of animations).
-    size_t animation_index = animations_waiting_for_target[i];
-    Animation* animation_waiting_for_target =
-        animations_[animation_index].get();
-    // Check for the run state again even though the animation was waiting
-    // for target because it might have changed the run state while handling
-    // previous animation in this loop (if they belong to same group).
-    if (animation_waiting_for_target->run_state() ==
-        Animation::WAITING_FOR_TARGET_AVAILABILITY) {
-      TargetProperties enqueued_properties;
-      bool affects_active_elements =
-          animation_waiting_for_target->affects_active_elements();
-      bool affects_pending_elements =
-          animation_waiting_for_target->affects_pending_elements();
-      enqueued_properties[animation_waiting_for_target->target_property_id()] =
-          true;
-      for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
-        if (animation_waiting_for_target->group() == animations_[j]->group()) {
-          enqueued_properties[animations_[j]->target_property_id()] = true;
-          affects_active_elements |= animations_[j]->affects_active_elements();
-          affects_pending_elements |=
-              animations_[j]->affects_pending_elements();
-        }
-      }
-
-      // Check to see if intersection of the list of properties affected by
-      // the group and the list of currently blocked properties is null, taking
-      // into account the type(s) of elements affected by the group. In any
-      // case, the group's target properties need to be added to the lists of
-      // blocked properties.
-      bool null_intersection = true;
-      for (int property = TargetProperty::FIRST_TARGET_PROPERTY;
-           property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) {
-        if (enqueued_properties[property]) {
-          if (affects_active_elements) {
-            if (blocked_properties_for_active_elements[property])
-              null_intersection = false;
-            else
-              blocked_properties_for_active_elements[property] = true;
-          }
-          if (affects_pending_elements) {
-            if (blocked_properties_for_pending_elements[property])
-              null_intersection = false;
-            else
-              blocked_properties_for_pending_elements[property] = true;
-          }
-        }
-      }
-
-      // If the intersection is null, then we are free to start the animations
-      // in the group.
-      if (null_intersection) {
-        animation_waiting_for_target->SetRunState(Animation::STARTING,
-                                                  monotonic_time);
-        for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
-          if (animation_waiting_for_target->group() ==
-              animations_[j]->group()) {
-            animations_[j]->SetRunState(Animation::STARTING, monotonic_time);
-          }
-        }
-      } else {
-        needs_to_start_animations_ = true;
-      }
-    }
-  }
-}
-
-void AnimationPlayer::PromoteStartedAnimations(base::TimeTicks monotonic_time,
-                                               AnimationEvents* events) {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->run_state() == Animation::STARTING &&
-        animations_[i]->affects_active_elements()) {
-      animations_[i]->SetRunState(Animation::RUNNING, monotonic_time);
-      if (!animations_[i]->has_set_start_time() &&
-          !animations_[i]->needs_synchronized_start_time())
-        animations_[i]->set_start_time(monotonic_time);
-      if (events) {
-        base::TimeTicks start_time;
-        if (animations_[i]->has_set_start_time())
-          start_time = animations_[i]->start_time();
-        else
-          start_time = monotonic_time;
-        AnimationEvent started_event(
-            AnimationEvent::STARTED, element_id_, animations_[i]->group(),
-            animations_[i]->target_property_id(), start_time);
-        started_event.is_impl_only = animations_[i]->is_impl_only();
-        if (started_event.is_impl_only) {
-          // Notify delegate directly, do not record the event.
-          if (animation_delegate_) {
-            animation_delegate_->NotifyAnimationStarted(
-                started_event.monotonic_time, started_event.target_property,
-                started_event.group_id);
-          }
-        } else {
-          events->events_.push_back(started_event);
-        }
-      }
-    }
-  }
-}
-
-void AnimationPlayer::MarkAnimationsForDeletion(base::TimeTicks monotonic_time,
-                                                AnimationEvents* events) {
-  bool marked_animations_for_deletions = false;
-  std::vector<size_t> animations_with_same_group_id;
-
-  animations_with_same_group_id.reserve(animations_.size());
-  // Non-aborted animations are marked for deletion after a corresponding
-  // AnimationEvent::FINISHED event is sent or received. This means that if
-  // we don't have an events vector, we must ensure that non-aborted animations
-  // have received a finished event before marking them for deletion.
-  for (size_t i = 0; i < animations_.size(); i++) {
-    int group_id = animations_[i]->group();
-    if (animations_[i]->run_state() == Animation::ABORTED) {
-      if (events && !animations_[i]->is_impl_only()) {
-        AnimationEvent aborted_event(
-            AnimationEvent::ABORTED, element_id_, group_id,
-            animations_[i]->target_property_id(), monotonic_time);
-        events->events_.push_back(aborted_event);
-      }
-      // If on the compositor or on the main thread and received finish event,
-      // animation can be marked for deletion.
-      if (events || animations_[i]->received_finished_event()) {
-        animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
-                                    monotonic_time);
-        marked_animations_for_deletions = true;
-      }
-      continue;
-    }
-
-    // If running on the compositor and need to complete an aborted animation
-    // on the main thread.
-    if (events &&
-        animations_[i]->run_state() ==
-            Animation::ABORTED_BUT_NEEDS_COMPLETION) {
-      AnimationEvent aborted_event(
-          AnimationEvent::TAKEOVER, element_id_, group_id,
-          animations_[i]->target_property_id(), monotonic_time);
-      aborted_event.animation_start_time = animations_[i]->start_time();
-      const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
-          animations_[i]->curve()->ToScrollOffsetAnimationCurve();
-      aborted_event.curve = scroll_offset_animation_curve->Clone();
-      // Notify the compositor that the animation is finished.
-      if (animation_delegate_) {
-        animation_delegate_->NotifyAnimationFinished(
-            aborted_event.monotonic_time, aborted_event.target_property,
-            aborted_event.group_id);
-      }
-      // Notify main thread.
-      events->events_.push_back(aborted_event);
-
-      // Remove the animation from the compositor.
-      animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
-                                  monotonic_time);
-      marked_animations_for_deletions = true;
-      continue;
-    }
-
-    bool all_anims_with_same_id_are_finished = false;
-
-    // Since deleting an animation on the main thread leads to its deletion
-    // on the impl thread, we only mark a FINISHED main thread animation for
-    // deletion once it has received a FINISHED event from the impl thread.
-    bool animation_i_will_send_or_has_received_finish_event =
-        animations_[i]->is_controlling_instance() ||
-        animations_[i]->is_impl_only() ||
-        animations_[i]->received_finished_event();
-    // If an animation is finished, and not already marked for deletion,
-    // find out if all other animations in the same group are also finished.
-    if (animations_[i]->run_state() == Animation::FINISHED &&
-        animation_i_will_send_or_has_received_finish_event) {
-      // Clear the animations_with_same_group_id if it was added for
-      // the previous animation's iteration.
-      if (animations_with_same_group_id.size() > 0)
-        animations_with_same_group_id.clear();
-      all_anims_with_same_id_are_finished = true;
-      for (size_t j = 0; j < animations_.size(); ++j) {
-        bool animation_j_will_send_or_has_received_finish_event =
-            animations_[j]->is_controlling_instance() ||
-            animations_[j]->is_impl_only() ||
-            animations_[j]->received_finished_event();
-        if (group_id == animations_[j]->group()) {
-          if (!animations_[j]->is_finished() ||
-              (animations_[j]->run_state() == Animation::FINISHED &&
-               !animation_j_will_send_or_has_received_finish_event)) {
-            all_anims_with_same_id_are_finished = false;
-            break;
-          } else if (j >= i &&
-                     animations_[j]->run_state() != Animation::ABORTED) {
-            // Mark down the animations which belong to the same group
-            // and is not yet aborted. If this current iteration finds that all
-            // animations with same ID are finished, then the marked
-            // animations below will be set to WAITING_FOR_DELETION in next
-            // iteration.
-            animations_with_same_group_id.push_back(j);
-          }
-        }
-      }
-    }
-    if (all_anims_with_same_id_are_finished) {
-      // We now need to remove all animations with the same group id as
-      // group_id (and send along animation finished notifications, if
-      // necessary).
-      for (size_t j = 0; j < animations_with_same_group_id.size(); j++) {
-        size_t animation_index = animations_with_same_group_id[j];
-        if (events) {
-          AnimationEvent finished_event(
-              AnimationEvent::FINISHED, element_id_,
-              animations_[animation_index]->group(),
-              animations_[animation_index]->target_property_id(),
-              monotonic_time);
-          finished_event.is_impl_only =
-              animations_[animation_index]->is_impl_only();
-          if (finished_event.is_impl_only) {
-            // Notify delegate directly, do not record the event.
-            if (animation_delegate_) {
-              animation_delegate_->NotifyAnimationFinished(
-                  finished_event.monotonic_time, finished_event.target_property,
-                  finished_event.group_id);
-            }
-          } else {
-            events->events_.push_back(finished_event);
-          }
-        }
-        animations_[animation_index]->SetRunState(
-            Animation::WAITING_FOR_DELETION, monotonic_time);
-      }
-      marked_animations_for_deletions = true;
-    }
-  }
-
-  // Notify about animations waiting for deletion.
-  // We need to purge animations marked for deletion, which happens in
-  // PushProperties().
-  if (marked_animations_for_deletions)
-    SetNeedsPushProperties();
-}
-
-void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time,
-                                    Animation* animation,
-                                    AnimationTarget* target) {
-  if ((animation->run_state() != Animation::STARTING &&
-       animation->run_state() != Animation::RUNNING &&
-       animation->run_state() != Animation::PAUSED) ||
-      !animation->InEffect(monotonic_time)) {
-    return;
-  }
-
-  AnimationCurve* curve = animation->curve();
-  base::TimeDelta trimmed =
-      animation->TrimTimeToCurrentIteration(monotonic_time);
-
-  switch (curve->Type()) {
-    case AnimationCurve::TRANSFORM:
-      target->NotifyClientTransformOperationsAnimated(
-          curve->ToTransformAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-    case AnimationCurve::FLOAT:
-      target->NotifyClientFloatAnimated(
-          curve->ToFloatAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-    case AnimationCurve::FILTER:
-      target->NotifyClientFilterAnimated(
-          curve->ToFilterAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-    case AnimationCurve::COLOR:
-      target->NotifyClientColorAnimated(
-          curve->ToColorAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-    case AnimationCurve::SCROLL_OFFSET:
-      target->NotifyClientScrollOffsetAnimated(
-          curve->ToScrollOffsetAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-    case AnimationCurve::SIZE:
-      target->NotifyClientSizeAnimated(
-          curve->ToSizeAnimationCurve()->GetValue(trimmed),
-          animation->target_property_id(), animation);
-      break;
-  }
-}
-
-void AnimationPlayer::TickAnimations(base::TimeTicks monotonic_time) {
-  DCHECK(element_animations_);
-  for (auto& animation : animations_)
-    TickAnimation(monotonic_time, animation.get(), element_animations_.get());
-  last_tick_time_ = monotonic_time;
-}
-
-void AnimationPlayer::MarkFinishedAnimations(base::TimeTicks monotonic_time) {
-  bool animation_finished = false;
-
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (!animations_[i]->is_finished() &&
-        animations_[i]->IsFinishedAt(monotonic_time)) {
-      animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
-      animation_finished = true;
-      SetNeedsPushProperties();
-    }
-    if (!animations_[i]->affects_active_elements() &&
-        !animations_[i]->affects_pending_elements()) {
-      switch (animations_[i]->run_state()) {
-        case Animation::WAITING_FOR_TARGET_AVAILABILITY:
-        case Animation::STARTING:
-        case Animation::RUNNING:
-        case Animation::PAUSED:
-          animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
-          animation_finished = true;
-          break;
-        default:
-          break;
-      }
-    }
-  }
-
-  DCHECK(element_animations_);
-  if (animation_finished)
-    element_animations_->UpdateClientAnimationState();
+bool AnimationPlayer::has_any_animation() const {
+  return animation_ticker_->has_any_animation();
 }
 
 void AnimationPlayer::ActivateAnimations() {
-  bool animation_activated = false;
-
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->affects_active_elements() !=
-        animations_[i]->affects_pending_elements()) {
-      animation_activated = true;
-    }
-    animations_[i]->set_affects_active_elements(
-        animations_[i]->affects_pending_elements());
-  }
-
-  if (animation_activated)
-    element_animations_->UpdateClientAnimationState();
-
-  scroll_offset_animation_was_interrupted_ = false;
+  animation_ticker_->ActivateAnimations();
   UpdateTickingState(UpdateTickingType::NORMAL);
 }
 
 bool AnimationPlayer::HasOnlyTranslationTransforms(
     ElementListType list_type) const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->is_finished() ||
-        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
-      continue;
-
-    if ((list_type == ElementListType::ACTIVE &&
-         !animations_[i]->affects_active_elements()) ||
-        (list_type == ElementListType::PENDING &&
-         !animations_[i]->affects_pending_elements()))
-      continue;
-
-    const TransformAnimationCurve* transform_animation_curve =
-        animations_[i]->curve()->ToTransformAnimationCurve();
-    if (!transform_animation_curve->IsTranslation())
-      return false;
-  }
-
-  return true;
+  return animation_ticker_->HasOnlyTranslationTransforms(list_type);
 }
 
 bool AnimationPlayer::AnimationsPreserveAxisAlignment() const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->is_finished() ||
-        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
-      continue;
-
-    const TransformAnimationCurve* transform_animation_curve =
-        animations_[i]->curve()->ToTransformAnimationCurve();
-    if (!transform_animation_curve->PreservesAxisAlignment())
-      return false;
-  }
-
-  return true;
+  return animation_ticker_->AnimationsPreserveAxisAlignment();
 }
 
 bool AnimationPlayer::AnimationStartScale(ElementListType list_type,
                                           float* start_scale) const {
-  *start_scale = 0.f;
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->is_finished() ||
-        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
-      continue;
-
-    if ((list_type == ElementListType::ACTIVE &&
-         !animations_[i]->affects_active_elements()) ||
-        (list_type == ElementListType::PENDING &&
-         !animations_[i]->affects_pending_elements()))
-      continue;
-
-    bool forward_direction = true;
-    switch (animations_[i]->direction()) {
-      case Animation::Direction::NORMAL:
-      case Animation::Direction::ALTERNATE_NORMAL:
-        forward_direction = animations_[i]->playback_rate() >= 0.0;
-        break;
-      case Animation::Direction::REVERSE:
-      case Animation::Direction::ALTERNATE_REVERSE:
-        forward_direction = animations_[i]->playback_rate() < 0.0;
-        break;
-    }
-
-    const TransformAnimationCurve* transform_animation_curve =
-        animations_[i]->curve()->ToTransformAnimationCurve();
-    float animation_start_scale = 0.f;
-    if (!transform_animation_curve->AnimationStartScale(forward_direction,
-                                                        &animation_start_scale))
-      return false;
-    *start_scale = std::max(*start_scale, animation_start_scale);
-  }
-  return true;
+  return animation_ticker_->AnimationStartScale(list_type, start_scale);
 }
 
 bool AnimationPlayer::MaximumTargetScale(ElementListType list_type,
                                          float* max_scale) const {
-  *max_scale = 0.f;
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (animations_[i]->is_finished() ||
-        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
-      continue;
-
-    if ((list_type == ElementListType::ACTIVE &&
-         !animations_[i]->affects_active_elements()) ||
-        (list_type == ElementListType::PENDING &&
-         !animations_[i]->affects_pending_elements()))
-      continue;
-
-    bool forward_direction = true;
-    switch (animations_[i]->direction()) {
-      case Animation::Direction::NORMAL:
-      case Animation::Direction::ALTERNATE_NORMAL:
-        forward_direction = animations_[i]->playback_rate() >= 0.0;
-        break;
-      case Animation::Direction::REVERSE:
-      case Animation::Direction::ALTERNATE_REVERSE:
-        forward_direction = animations_[i]->playback_rate() < 0.0;
-        break;
-    }
-
-    const TransformAnimationCurve* transform_animation_curve =
-        animations_[i]->curve()->ToTransformAnimationCurve();
-    float animation_scale = 0.f;
-    if (!transform_animation_curve->MaximumTargetScale(forward_direction,
-                                                       &animation_scale))
-      return false;
-    *max_scale = std::max(*max_scale, animation_scale);
-  }
-
-  return true;
+  return animation_ticker_->MaximumTargetScale(list_type, max_scale);
 }
 
 bool AnimationPlayer::IsPotentiallyAnimatingProperty(
     TargetProperty::Type target_property,
     ElementListType list_type) const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (!animations_[i]->is_finished() &&
-        animations_[i]->target_property_id() == target_property) {
-      if ((list_type == ElementListType::ACTIVE &&
-           animations_[i]->affects_active_elements()) ||
-          (list_type == ElementListType::PENDING &&
-           animations_[i]->affects_pending_elements()))
-        return true;
-    }
-  }
-  return false;
+  return animation_ticker_->IsPotentiallyAnimatingProperty(target_property,
+                                                           list_type);
 }
 
 bool AnimationPlayer::IsCurrentlyAnimatingProperty(
     TargetProperty::Type target_property,
     ElementListType list_type) const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    if (!animations_[i]->is_finished() &&
-        animations_[i]->InEffect(last_tick_time_) &&
-        animations_[i]->target_property_id() == target_property) {
-      if ((list_type == ElementListType::ACTIVE &&
-           animations_[i]->affects_active_elements()) ||
-          (list_type == ElementListType::PENDING &&
-           animations_[i]->affects_pending_elements()))
-        return true;
-    }
-  }
-  return false;
-}
-
-bool AnimationPlayer::HasElementInActiveList() const {
-  DCHECK(element_animations_);
-  return element_animations_->has_element_in_active_list();
-}
-
-gfx::ScrollOffset AnimationPlayer::ScrollOffsetForAnimation() const {
-  DCHECK(element_animations_);
-  return element_animations_->ScrollOffsetForAnimation();
+  return animation_ticker_->IsCurrentlyAnimatingProperty(target_property,
+                                                         list_type);
 }
 
 Animation* AnimationPlayer::GetAnimation(
     TargetProperty::Type target_property) const {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    size_t index = animations_.size() - i - 1;
-    if (animations_[index]->target_property_id() == target_property)
-      return animations_[index].get();
-  }
-  return nullptr;
+  return animation_ticker_->GetAnimation(target_property);
 }
 
 Animation* AnimationPlayer::GetAnimationById(int animation_id) const {
-  for (size_t i = 0; i < animations_.size(); ++i)
-    if (animations_[i]->id() == animation_id)
-      return animations_[i].get();
-  return nullptr;
+  return animation_ticker_->GetAnimationById(animation_id);
 }
 
 void AnimationPlayer::GetPropertyAnimationState(
     PropertyAnimationState* pending_state,
     PropertyAnimationState* active_state) const {
-  pending_state->Clear();
-  active_state->Clear();
-
-  for (const auto& animation : animations_) {
-    if (!animation->is_finished()) {
-      bool in_effect = animation->InEffect(last_tick_time_);
-      bool active = animation->affects_active_elements();
-      bool pending = animation->affects_pending_elements();
-      int property = animation->target_property_id();
-
-      if (pending)
-        pending_state->potentially_animating[property] = true;
-      if (pending && in_effect)
-        pending_state->currently_running[property] = true;
-
-      if (active)
-        active_state->potentially_animating[property] = true;
-      if (active && in_effect)
-        active_state->currently_running[property] = true;
-    }
-  }
-}
-
-void AnimationPlayer::MarkAbortedAnimationsForDeletion(
-    AnimationPlayer* animation_player_impl) const {
-  bool animation_aborted = false;
-
-  auto& animations_impl = animation_player_impl->animations_;
-  for (const auto& animation_impl : animations_impl) {
-    // If the animation has been aborted on the main thread, mark it for
-    // deletion.
-    if (Animation* animation = GetAnimationById(animation_impl->id())) {
-      if (animation->run_state() == Animation::ABORTED) {
-        animation_impl->SetRunState(Animation::WAITING_FOR_DELETION,
-                                    animation_player_impl->last_tick_time_);
-        animation->SetRunState(Animation::WAITING_FOR_DELETION,
-                               last_tick_time_);
-        animation_aborted = true;
-      }
-    }
-  }
-
-  if (element_animations_ && animation_aborted)
-    element_animations_->SetNeedsUpdateImplClientState();
-}
-
-void AnimationPlayer::PurgeAnimationsMarkedForDeletion(bool impl_only) {
-  base::EraseIf(
-      animations_, [impl_only](const std::unique_ptr<Animation>& animation) {
-        return animation->run_state() == Animation::WAITING_FOR_DELETION &&
-               (!impl_only || animation->is_impl_only());
-      });
-}
-
-void AnimationPlayer::PushNewAnimationsToImplThread(
-    AnimationPlayer* animation_player_impl) const {
-  // Any new animations owned by the main thread's AnimationPlayer are cloned
-  // and added to the impl thread's AnimationPlayer.
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    // If the animation is already running on the impl thread, there is no
-    // need to copy it over.
-    if (animation_player_impl->GetAnimationById(animations_[i]->id()))
-      continue;
-
-    if (animations_[i]->target_property_id() == TargetProperty::SCROLL_OFFSET &&
-        !animations_[i]
-             ->curve()
-             ->ToScrollOffsetAnimationCurve()
-             ->HasSetInitialValue()) {
-      gfx::ScrollOffset current_scroll_offset;
-      if (animation_player_impl->HasElementInActiveList()) {
-        current_scroll_offset =
-            animation_player_impl->ScrollOffsetForAnimation();
-      } else {
-        // The owning layer isn't yet in the active tree, so the main thread
-        // scroll offset will be up to date.
-        current_scroll_offset = ScrollOffsetForAnimation();
-      }
-      animations_[i]->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
-          current_scroll_offset);
-    }
-
-    // The new animation should be set to run as soon as possible.
-    Animation::RunState initial_run_state =
-        Animation::WAITING_FOR_TARGET_AVAILABILITY;
-    std::unique_ptr<Animation> to_add(
-        animations_[i]->CloneAndInitialize(initial_run_state));
-    DCHECK(!to_add->needs_synchronized_start_time());
-    to_add->set_affects_active_elements(false);
-    animation_player_impl->AddAnimation(std::move(to_add));
-  }
-}
-
-static bool IsCompleted(Animation* animation,
-                        const AnimationPlayer* main_thread_player) {
-  if (animation->is_impl_only()) {
-    return (animation->run_state() == Animation::WAITING_FOR_DELETION);
-  } else {
-    Animation* main_thread_animation =
-        main_thread_player->GetAnimationById(animation->id());
-    return !main_thread_animation || main_thread_animation->is_finished();
-  }
-}
-
-void AnimationPlayer::RemoveAnimationsCompletedOnMainThread(
-    AnimationPlayer* animation_player_impl) const {
-  bool animation_completed = false;
-
-  // Animations removed on the main thread should no longer affect pending
-  // elements, and should stop affecting active elements after the next call
-  // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed
-  // immediately.
-  auto& animations = animation_player_impl->animations_;
-  for (const auto& animation : animations) {
-    if (IsCompleted(animation.get(), this)) {
-      animation->set_affects_pending_elements(false);
-      animation_completed = true;
-    }
-  }
-  auto affects_active_only_and_is_waiting_for_deletion =
-      [](const std::unique_ptr<Animation>& animation) {
-        return animation->run_state() == Animation::WAITING_FOR_DELETION &&
-               !animation->affects_pending_elements();
-      };
-  base::EraseIf(animations, affects_active_only_and_is_waiting_for_deletion);
-
-  if (element_animations_ && animation_completed)
-    element_animations_->SetNeedsUpdateImplClientState();
+  animation_ticker_->GetPropertyAnimationState(pending_state, active_state);
 }
 
 void AnimationPlayer::PushPropertiesToImplThread(
     AnimationPlayer* animation_player_impl) {
-  for (size_t i = 0; i < animations_.size(); ++i) {
-    Animation* current_impl =
-        animation_player_impl->GetAnimationById(animations_[i]->id());
-    if (current_impl)
-      animations_[i]->PushPropertiesTo(current_impl);
-  }
+  animation_ticker_->PushPropertiesToImplThread(
+      animation_player_impl->animation_ticker_.get());
+}
 
-  animation_player_impl->scroll_offset_animation_was_interrupted_ =
-      scroll_offset_animation_was_interrupted_;
-  scroll_offset_animation_was_interrupted_ = false;
+bool AnimationPlayer::scroll_offset_animation_was_interrupted() const {
+  return animation_ticker_->scroll_offset_animation_was_interrupted();
 }
 
 std::string AnimationPlayer::ToString() const {
   return base::StringPrintf(
       "AnimationPlayer{id=%d, element_id=%s, animations=[%s]}", id_,
-      element_id_.ToString().c_str(), AnimationsToString().c_str());
-}
-
-std::string AnimationPlayer::AnimationsToString() const {
-  std::string str;
-  for (size_t i = 0; i < animations_.size(); i++) {
-    if (i > 0)
-      str.append(", ");
-    str.append(animations_[i]->ToString());
-  }
-  return str;
+      animation_ticker_->element_id().ToString().c_str(),
+      animation_ticker_->AnimationsToString().c_str());
 }
 
 }  // namespace cc
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h
index 6a543d6..fdf11a7 100644
--- a/cc/animation/animation_player.h
+++ b/cc/animation/animation_player.h
@@ -22,17 +22,24 @@
 class AnimationEvents;
 class AnimationHost;
 class AnimationTimeline;
+class AnimationTicker;
 struct AnimationEvent;
 struct PropertyAnimationState;
 
-// An AnimationPlayer owns all animations to be run on particular CC Layer.
-// Multiple AnimationPlayers can be attached to one layer. In this case,
-// they share common ElementAnimations so the
-// ElementAnimations-to-Layer relationship is 1:1.
-// For now, the blink logic is responsible for handling of conflicting
-// same-property animations.
-// Each AnimationPlayer has its copy on the impl thread.
-// This is a CC counterpart for blink::AnimationPlayer (in 1:1 relationship).
+// An AnimationPlayer manages grouped sets of animations (each set of which are
+// stored in an AnimationTicker), and handles the interaction with the
+// AnimationHost and AnimationTimeline.
+//
+// This class is a CC counterpart for blink::Animation, currently in a 1:1
+// relationship. Currently the blink logic is responsible for handling of
+// conflicting same-property animations.
+//
+// Each cc AnimationPlayer has a copy on the impl thread, and will take care of
+// synchronizing properties to/from the impl thread when requested.
+//
+// NOTE(smcgruer): As of 2017/09/06 there is a 1:1 relationship between
+// AnimationPlayer and the AnimationTicker. This is intended to become a 1:N
+// relationship to allow for grouped animations.
 class CC_ANIMATION_EXPORT AnimationPlayer
     : public base::RefCounted<AnimationPlayer> {
  public:
@@ -40,13 +47,14 @@
   scoped_refptr<AnimationPlayer> CreateImplInstance() const;
 
   int id() const { return id_; }
-  ElementId element_id() const { return element_id_; }
+  ElementId element_id() const;
 
   // Parent AnimationHost. AnimationPlayer can be detached from
   // AnimationTimeline.
   AnimationHost* animation_host() { return animation_host_; }
   const AnimationHost* animation_host() const { return animation_host_; }
   void SetAnimationHost(AnimationHost* animation_host);
+  bool has_animation_host() const { return !!animation_host_; }
 
   // Parent AnimationTimeline.
   AnimationTimeline* animation_timeline() { return animation_timeline_; }
@@ -55,10 +63,7 @@
   }
   void SetAnimationTimeline(AnimationTimeline* timeline);
 
-  // ElementAnimations object where this player is listed.
-  scoped_refptr<ElementAnimations> element_animations() const {
-    return element_animations_;
-  }
+  scoped_refptr<ElementAnimations> element_animations() const;
 
   void set_animation_delegate(AnimationDelegate* delegate) {
     animation_delegate_ = delegate;
@@ -80,6 +85,7 @@
   void UpdateState(bool start_ready_animations, AnimationEvents* events);
 
   void UpdateTickingState(UpdateTickingType type);
+  void AddToTicking();
   void RemoveFromTicking();
 
   // AnimationDelegate routing.
@@ -89,34 +95,22 @@
   void NotifyAnimationTakeover(const AnimationEvent& event);
   bool NotifyAnimationFinishedForTesting(TargetProperty::Type target_property,
                                          int group_id);
+  // TODO(smcgruer): Once ElementAnimations points at AnimationTicker directly,
+  // merge these methods with the above.
+  void NotifyImplOnlyAnimationStarted(AnimationEvent&);
+  void NotifyImplOnlyAnimationFinished(AnimationEvent&);
+  void NotifyAnimationTakeoverByMain(AnimationEvent&);
 
   // Returns true if there are any animations that have neither finished nor
   // aborted.
   bool HasTickingAnimation() const;
 
   // Returns true if there are any animations at all to process.
-  bool has_any_animation() const { return !animations_.empty(); }
+  bool has_any_animation() const;
 
   bool needs_push_properties() const { return needs_push_properties_; }
   void SetNeedsPushProperties();
 
-  bool HasNonDeletedAnimation() const;
-
-  bool needs_to_start_animations() const { return needs_to_start_animations_; }
-
-  void StartAnimations(base::TimeTicks monotonic_time);
-  void PromoteStartedAnimations(base::TimeTicks monotonic_time,
-                                AnimationEvents* events);
-  void MarkAnimationsForDeletion(base::TimeTicks monotonic_time,
-                                 AnimationEvents* events);
-
-  static void TickAnimation(base::TimeTicks monotonic_time,
-                            Animation* animation,
-                            AnimationTarget* target);
-  void TickAnimations(base::TimeTicks monotonic_time);
-
-  void MarkFinishedAnimations(base::TimeTicks monotonic_time);
-
   // Make animations affect active elements if and only if they affect
   // pending elements. Any animations that no longer affect any elements
   // are deleted.
@@ -146,81 +140,46 @@
   bool IsCurrentlyAnimatingProperty(TargetProperty::Type target_property,
                                     ElementListType list_type) const;
 
-  bool HasElementInActiveList() const;
-  gfx::ScrollOffset ScrollOffsetForAnimation() const;
-
   // Returns the animation animating the given property that is either
   // running, or is next to run, if such an animation exists.
   Animation* GetAnimation(TargetProperty::Type target_property) const;
 
   // Returns animation for the given unique animation id.
+  // TODO(smcgruer): Remove, only tests call this and they should call on the
+  // AnimationTicker instead.
   Animation* GetAnimationById(int animation_id) const;
 
   void GetPropertyAnimationState(PropertyAnimationState* pending_state,
                                  PropertyAnimationState* active_state) const;
 
-  // When a scroll animation is removed on the main thread, its compositor
-  // thread counterpart continues producing scroll deltas until activation.
-  // These scroll deltas need to be cleared at activation, so that the active
-  // element's scroll offset matches the offset provided by the main thread
-  // rather than a combination of this offset and scroll deltas produced by
-  // the removed animation. This is to provide the illusion of synchronicity to
-  // JS that simultaneously removes an animation and sets the scroll offset.
-  bool scroll_offset_animation_was_interrupted() const {
-    return scroll_offset_animation_was_interrupted_;
-  }
+  bool scroll_offset_animation_was_interrupted() const;
 
   std::string ToString() const;
 
+  void SetNeedsCommit();
+
  private:
   friend class base::RefCounted<AnimationPlayer>;
 
   explicit AnimationPlayer(int id);
   ~AnimationPlayer();
 
-  void SetNeedsCommit();
-
   void RegisterPlayer();
   void UnregisterPlayer();
 
   void BindElementAnimations();
   void UnbindElementAnimations();
 
-  void AnimationAdded();
-
-  void MarkAbortedAnimationsForDeletion(
-      AnimationPlayer* animation_player_impl) const;
-  void PurgeAnimationsMarkedForDeletion(bool impl_only);
-  void PushNewAnimationsToImplThread(
-      AnimationPlayer* animation_player_impl) const;
-  void RemoveAnimationsCompletedOnMainThread(
-      AnimationPlayer* animation_player_impl) const;
   void PushPropertiesToImplThread(AnimationPlayer* animation_player_impl);
 
-  std::string AnimationsToString() const;
-
-  using Animations = std::vector<std::unique_ptr<Animation>>;
-  Animations animations_;
-
   AnimationHost* animation_host_;
   AnimationTimeline* animation_timeline_;
-  // element_animations isn't null if player attached to an element (layer).
-  scoped_refptr<ElementAnimations> element_animations_;
   AnimationDelegate* animation_delegate_;
 
   int id_;
-  ElementId element_id_;
   bool needs_push_properties_;
-  base::TimeTicks last_tick_time_;
 
-  // Only try to start animations when new animations are added or when the
-  // previous attempt at starting animations failed to start all animations.
-  bool needs_to_start_animations_;
-
-  // This is used to ensure that we don't spam the animation host.
-  bool is_ticking_;
-
-  bool scroll_offset_animation_was_interrupted_;
+  std::unique_ptr<AnimationTicker> animation_ticker_;
 
   DISALLOW_COPY_AND_ASSIGN(AnimationPlayer);
 };
diff --git a/cc/animation/animation_ticker.cc b/cc/animation/animation_ticker.cc
new file mode 100644
index 0000000..b534362
--- /dev/null
+++ b/cc/animation/animation_ticker.cc
@@ -0,0 +1,964 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "cc/animation/animation_ticker.h"
+
+#include "base/stl_util.h"
+#include "base/time/time.h"
+#include "cc/animation/animation.h"
+#include "cc/animation/animation_curve.h"
+#include "cc/animation/animation_host.h"
+#include "cc/animation/animation_player.h"
+#include "cc/animation/scroll_offset_animation_curve.h"
+#include "cc/animation/transform_operations.h"
+#include "cc/trees/property_animation_state.h"
+
+namespace cc {
+
+AnimationTicker::AnimationTicker(AnimationPlayer* animation_player)
+    : animation_player_(animation_player),
+      element_animations_(),
+      needs_to_start_animations_(false),
+      scroll_offset_animation_was_interrupted_(false),
+      is_ticking_(false) {
+  DCHECK(animation_player_);
+}
+
+AnimationTicker::~AnimationTicker() {
+  DCHECK(!has_bound_element_animations());
+}
+
+void AnimationTicker::BindElementAnimations(AnimationHost* host) {
+  DCHECK(!element_animations_);
+  element_animations_ = host->GetElementAnimationsForElementId(element_id_);
+  DCHECK(element_animations_);
+
+  if (has_any_animation())
+    AnimationAdded();
+}
+
+void AnimationTicker::UnbindElementAnimations() {
+  element_animations_ = nullptr;
+}
+
+void AnimationTicker::AttachElement(ElementId element_id) {
+  DCHECK(!element_id_);
+  DCHECK(element_id);
+  element_id_ = element_id;
+}
+
+void AnimationTicker::DetachElement() {
+  DCHECK(element_id_);
+  element_id_ = ElementId();
+}
+
+void AnimationTicker::Tick(base::TimeTicks monotonic_time) {
+  DCHECK(has_bound_element_animations());
+  if (!element_animations_->has_element_in_any_list())
+    return;
+
+  if (needs_to_start_animations_)
+    StartAnimations(monotonic_time);
+
+  for (auto& animation : animations_)
+    TickAnimation(monotonic_time, animation.get(), element_animations_.get());
+
+  last_tick_time_ = monotonic_time;
+  element_animations_->UpdateClientAnimationState();
+}
+
+void AnimationTicker::TickAnimation(base::TimeTicks monotonic_time,
+                                    Animation* animation,
+                                    AnimationTarget* target) {
+  if ((animation->run_state() != Animation::STARTING &&
+       animation->run_state() != Animation::RUNNING &&
+       animation->run_state() != Animation::PAUSED) ||
+      !animation->InEffect(monotonic_time)) {
+    return;
+  }
+
+  AnimationCurve* curve = animation->curve();
+  base::TimeDelta trimmed =
+      animation->TrimTimeToCurrentIteration(monotonic_time);
+
+  switch (curve->Type()) {
+    case AnimationCurve::TRANSFORM:
+      target->NotifyClientTransformOperationsAnimated(
+          curve->ToTransformAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+    case AnimationCurve::FLOAT:
+      target->NotifyClientFloatAnimated(
+          curve->ToFloatAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+    case AnimationCurve::FILTER:
+      target->NotifyClientFilterAnimated(
+          curve->ToFilterAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+    case AnimationCurve::COLOR:
+      target->NotifyClientColorAnimated(
+          curve->ToColorAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+    case AnimationCurve::SCROLL_OFFSET:
+      target->NotifyClientScrollOffsetAnimated(
+          curve->ToScrollOffsetAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+    case AnimationCurve::SIZE:
+      target->NotifyClientSizeAnimated(
+          curve->ToSizeAnimationCurve()->GetValue(trimmed),
+          animation->target_property_id(), animation);
+      break;
+  }
+}
+
+void AnimationTicker::RemoveFromTicking() {
+  is_ticking_ = false;
+  last_tick_time_ = base::TimeTicks();
+}
+
+void AnimationTicker::UpdateState(bool start_ready_animations,
+                                  AnimationEvents* events) {
+  DCHECK(has_bound_element_animations());
+  if (!element_animations_->has_element_in_active_list())
+    return;
+
+  // Animate hasn't been called, this happens if an element has been added
+  // between the Commit and Draw phases.
+  if (last_tick_time_ == base::TimeTicks())
+    return;
+
+  if (start_ready_animations)
+    PromoteStartedAnimations(events);
+
+  MarkFinishedAnimations(last_tick_time_);
+  MarkAnimationsForDeletion(last_tick_time_, events);
+  PurgeAnimationsMarkedForDeletion(/* impl_only */ true);
+
+  if (start_ready_animations) {
+    if (needs_to_start_animations_) {
+      StartAnimations(last_tick_time_);
+      PromoteStartedAnimations(events);
+    }
+  }
+}
+
+void AnimationTicker::UpdateTickingState(UpdateTickingType type) {
+  bool force = type == UpdateTickingType::FORCE;
+  if (animation_player_->has_animation_host()) {
+    bool was_ticking = is_ticking_;
+    is_ticking_ = HasNonDeletedAnimation();
+
+    bool has_element_in_any_list =
+        element_animations_->has_element_in_any_list();
+
+    if (is_ticking_ && ((!was_ticking && has_element_in_any_list) || force)) {
+      animation_player_->AddToTicking();
+    } else if (!is_ticking_ && (was_ticking || force)) {
+      animation_player_->RemoveFromTicking();
+    }
+  }
+}
+
+void AnimationTicker::AddAnimation(std::unique_ptr<Animation> animation) {
+  AnimationHost* animation_host = animation_player_->animation_host();
+  DCHECK(animation->target_property_id() != TargetProperty::SCROLL_OFFSET ||
+         (animation_host && animation_host->SupportsScrollAnimations()));
+  DCHECK(!animation->is_impl_only() ||
+         animation->target_property_id() == TargetProperty::SCROLL_OFFSET);
+
+  animations_.push_back(std::move(animation));
+
+  if (has_bound_element_animations()) {
+    AnimationAdded();
+    animation_player_->SetNeedsPushProperties();
+  }
+}
+
+void AnimationTicker::PauseAnimation(int animation_id, double time_offset) {
+  const base::TimeDelta time_delta = base::TimeDelta::FromSecondsD(time_offset);
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->id() == animation_id) {
+      animations_[i]->SetRunState(Animation::PAUSED,
+                                  time_delta + animations_[i]->start_time() +
+                                      animations_[i]->time_offset());
+    }
+  }
+
+  if (has_bound_element_animations()) {
+    animation_player_->SetNeedsCommit();
+    animation_player_->SetNeedsPushProperties();
+  }
+}
+
+void AnimationTicker::RemoveAnimation(int animation_id) {
+  bool animation_removed = false;
+
+  // Since we want to use the animations that we're going to remove, we need to
+  // use a stable_parition here instead of remove_if. Remove_if leaves the
+  // removed items in an unspecified state.
+  auto animations_to_remove = std::stable_partition(
+      animations_.begin(), animations_.end(),
+      [animation_id](const std::unique_ptr<Animation>& animation) {
+        return animation->id() != animation_id;
+      });
+  for (auto it = animations_to_remove; it != animations_.end(); ++it) {
+    if ((*it)->target_property_id() == TargetProperty::SCROLL_OFFSET) {
+      if (has_bound_element_animations())
+        scroll_offset_animation_was_interrupted_ = true;
+    } else if (!(*it)->is_finished()) {
+      animation_removed = true;
+    }
+  }
+
+  animations_.erase(animations_to_remove, animations_.end());
+
+  if (has_bound_element_animations()) {
+    animation_player_->UpdateTickingState(UpdateTickingType::NORMAL);
+    if (animation_removed)
+      element_animations_->UpdateClientAnimationState();
+    animation_player_->SetNeedsCommit();
+    animation_player_->SetNeedsPushProperties();
+  }
+}
+
+void AnimationTicker::AbortAnimation(int animation_id) {
+  if (Animation* animation = GetAnimationById(animation_id)) {
+    if (!animation->is_finished()) {
+      animation->SetRunState(Animation::ABORTED, last_tick_time_);
+      if (has_bound_element_animations())
+        element_animations_->UpdateClientAnimationState();
+    }
+  }
+
+  if (has_bound_element_animations()) {
+    animation_player_->SetNeedsCommit();
+    animation_player_->SetNeedsPushProperties();
+  }
+}
+
+void AnimationTicker::AbortAnimations(TargetProperty::Type target_property,
+                                      bool needs_completion) {
+  if (needs_completion)
+    DCHECK(target_property == TargetProperty::SCROLL_OFFSET);
+
+  bool aborted_animation = false;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->target_property_id() == target_property &&
+        !animations_[i]->is_finished()) {
+      // Currently only impl-only scroll offset animations can be completed on
+      // the main thread.
+      if (needs_completion && animations_[i]->is_impl_only()) {
+        animations_[i]->SetRunState(Animation::ABORTED_BUT_NEEDS_COMPLETION,
+                                    last_tick_time_);
+      } else {
+        animations_[i]->SetRunState(Animation::ABORTED, last_tick_time_);
+      }
+      aborted_animation = true;
+    }
+  }
+
+  if (has_bound_element_animations()) {
+    if (aborted_animation)
+      element_animations_->UpdateClientAnimationState();
+    animation_player_->SetNeedsCommit();
+    animation_player_->SetNeedsPushProperties();
+  }
+}
+
+void AnimationTicker::ActivateAnimations() {
+  DCHECK(has_bound_element_animations());
+
+  bool animation_activated = false;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->affects_active_elements() !=
+        animations_[i]->affects_pending_elements()) {
+      animation_activated = true;
+    }
+    animations_[i]->set_affects_active_elements(
+        animations_[i]->affects_pending_elements());
+  }
+
+  if (animation_activated)
+    element_animations_->UpdateClientAnimationState();
+
+  scroll_offset_animation_was_interrupted_ = false;
+}
+
+void AnimationTicker::AnimationAdded() {
+  DCHECK(has_bound_element_animations());
+
+  animation_player_->SetNeedsCommit();
+  needs_to_start_animations_ = true;
+
+  UpdateTickingState(UpdateTickingType::NORMAL);
+  element_animations_->UpdateClientAnimationState();
+}
+
+bool AnimationTicker::NotifyAnimationStarted(const AnimationEvent& event) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property_id() == event.target_property &&
+        animations_[i]->needs_synchronized_start_time()) {
+      animations_[i]->set_needs_synchronized_start_time(false);
+      if (!animations_[i]->has_set_start_time())
+        animations_[i]->set_start_time(event.monotonic_time);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool AnimationTicker::NotifyAnimationFinished(const AnimationEvent& event) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property_id() == event.target_property) {
+      animations_[i]->set_received_finished_event(true);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool AnimationTicker::NotifyAnimationAborted(const AnimationEvent& event) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->group() == event.group_id &&
+        animations_[i]->target_property_id() == event.target_property) {
+      animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time);
+      animations_[i]->set_received_finished_event(true);
+      return true;
+    }
+  }
+  return false;
+}
+
+bool AnimationTicker::HasTickingAnimation() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished())
+      return true;
+  }
+  return false;
+}
+
+bool AnimationTicker::HasNonDeletedAnimation() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() != Animation::WAITING_FOR_DELETION)
+      return true;
+  }
+  return false;
+}
+
+bool AnimationTicker::HasOnlyTranslationTransforms(
+    ElementListType list_type) const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
+      continue;
+
+    if ((list_type == ElementListType::ACTIVE &&
+         !animations_[i]->affects_active_elements()) ||
+        (list_type == ElementListType::PENDING &&
+         !animations_[i]->affects_pending_elements()))
+      continue;
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    if (!transform_animation_curve->IsTranslation())
+      return false;
+  }
+  return true;
+}
+
+bool AnimationTicker::AnimationsPreserveAxisAlignment() const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
+      continue;
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    if (!transform_animation_curve->PreservesAxisAlignment())
+      return false;
+  }
+  return true;
+}
+
+bool AnimationTicker::AnimationStartScale(ElementListType list_type,
+                                          float* start_scale) const {
+  *start_scale = 0.f;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
+      continue;
+
+    if ((list_type == ElementListType::ACTIVE &&
+         !animations_[i]->affects_active_elements()) ||
+        (list_type == ElementListType::PENDING &&
+         !animations_[i]->affects_pending_elements()))
+      continue;
+
+    bool forward_direction = true;
+    switch (animations_[i]->direction()) {
+      case Animation::Direction::NORMAL:
+      case Animation::Direction::ALTERNATE_NORMAL:
+        forward_direction = animations_[i]->playback_rate() >= 0.0;
+        break;
+      case Animation::Direction::REVERSE:
+      case Animation::Direction::ALTERNATE_REVERSE:
+        forward_direction = animations_[i]->playback_rate() < 0.0;
+        break;
+    }
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    float animation_start_scale = 0.f;
+    if (!transform_animation_curve->AnimationStartScale(forward_direction,
+                                                        &animation_start_scale))
+      return false;
+    *start_scale = std::max(*start_scale, animation_start_scale);
+  }
+  return true;
+}
+
+bool AnimationTicker::MaximumTargetScale(ElementListType list_type,
+                                         float* max_scale) const {
+  *max_scale = 0.f;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->is_finished() ||
+        animations_[i]->target_property_id() != TargetProperty::TRANSFORM)
+      continue;
+
+    if ((list_type == ElementListType::ACTIVE &&
+         !animations_[i]->affects_active_elements()) ||
+        (list_type == ElementListType::PENDING &&
+         !animations_[i]->affects_pending_elements()))
+      continue;
+
+    bool forward_direction = true;
+    switch (animations_[i]->direction()) {
+      case Animation::Direction::NORMAL:
+      case Animation::Direction::ALTERNATE_NORMAL:
+        forward_direction = animations_[i]->playback_rate() >= 0.0;
+        break;
+      case Animation::Direction::REVERSE:
+      case Animation::Direction::ALTERNATE_REVERSE:
+        forward_direction = animations_[i]->playback_rate() < 0.0;
+        break;
+    }
+
+    const TransformAnimationCurve* transform_animation_curve =
+        animations_[i]->curve()->ToTransformAnimationCurve();
+    float animation_scale = 0.f;
+    if (!transform_animation_curve->MaximumTargetScale(forward_direction,
+                                                       &animation_scale))
+      return false;
+    *max_scale = std::max(*max_scale, animation_scale);
+  }
+
+  return true;
+}
+
+bool AnimationTicker::IsPotentiallyAnimatingProperty(
+    TargetProperty::Type target_property,
+    ElementListType list_type) const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished() &&
+        animations_[i]->target_property_id() == target_property) {
+      if ((list_type == ElementListType::ACTIVE &&
+           animations_[i]->affects_active_elements()) ||
+          (list_type == ElementListType::PENDING &&
+           animations_[i]->affects_pending_elements()))
+        return true;
+    }
+  }
+  return false;
+}
+
+bool AnimationTicker::IsCurrentlyAnimatingProperty(
+    TargetProperty::Type target_property,
+    ElementListType list_type) const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished() &&
+        animations_[i]->InEffect(last_tick_time_) &&
+        animations_[i]->target_property_id() == target_property) {
+      if ((list_type == ElementListType::ACTIVE &&
+           animations_[i]->affects_active_elements()) ||
+          (list_type == ElementListType::PENDING &&
+           animations_[i]->affects_pending_elements()))
+        return true;
+    }
+  }
+  return false;
+}
+
+Animation* AnimationTicker::GetAnimation(
+    TargetProperty::Type target_property) const {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    size_t index = animations_.size() - i - 1;
+    if (animations_[index]->target_property_id() == target_property)
+      return animations_[index].get();
+  }
+  return nullptr;
+}
+
+Animation* AnimationTicker::GetAnimationById(int animation_id) const {
+  for (size_t i = 0; i < animations_.size(); ++i)
+    if (animations_[i]->id() == animation_id)
+      return animations_[i].get();
+  return nullptr;
+}
+
+void AnimationTicker::GetPropertyAnimationState(
+    PropertyAnimationState* pending_state,
+    PropertyAnimationState* active_state) const {
+  pending_state->Clear();
+  active_state->Clear();
+
+  for (const auto& animation : animations_) {
+    if (!animation->is_finished()) {
+      bool in_effect = animation->InEffect(last_tick_time_);
+      bool active = animation->affects_active_elements();
+      bool pending = animation->affects_pending_elements();
+      int property = animation->target_property_id();
+
+      if (pending)
+        pending_state->potentially_animating[property] = true;
+      if (pending && in_effect)
+        pending_state->currently_running[property] = true;
+
+      if (active)
+        active_state->potentially_animating[property] = true;
+      if (active && in_effect)
+        active_state->currently_running[property] = true;
+    }
+  }
+}
+
+void AnimationTicker::MarkAbortedAnimationsForDeletion(
+    AnimationTicker* animation_ticker_impl) {
+  bool animation_aborted = false;
+
+  auto& animations_impl = animation_ticker_impl->animations_;
+  for (const auto& animation_impl : animations_impl) {
+    // If the animation has been aborted on the main thread, mark it for
+    // deletion.
+    if (Animation* animation = GetAnimationById(animation_impl->id())) {
+      if (animation->run_state() == Animation::ABORTED) {
+        animation_impl->SetRunState(Animation::WAITING_FOR_DELETION,
+                                    animation_ticker_impl->last_tick_time_);
+        animation->SetRunState(Animation::WAITING_FOR_DELETION,
+                               last_tick_time_);
+        animation_aborted = true;
+      }
+    }
+  }
+
+  if (has_bound_element_animations() && animation_aborted)
+    element_animations_->SetNeedsUpdateImplClientState();
+}
+
+void AnimationTicker::PurgeAnimationsMarkedForDeletion(bool impl_only) {
+  base::EraseIf(
+      animations_, [impl_only](const std::unique_ptr<Animation>& animation) {
+        return animation->run_state() == Animation::WAITING_FOR_DELETION &&
+               (!impl_only || animation->is_impl_only());
+      });
+}
+
+void AnimationTicker::PushNewAnimationsToImplThread(
+    AnimationTicker* animation_ticker_impl) const {
+  // Any new animations owned by the main thread's AnimationPlayer are cloned
+  // and added to the impl thread's AnimationPlayer.
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    const auto& anim = animations_[i];
+
+    // If the animation is already running on the impl thread, there is no
+    // need to copy it over.
+    if (animation_ticker_impl->GetAnimationById(anim->id()))
+      continue;
+
+    if (anim->target_property_id() == TargetProperty::SCROLL_OFFSET &&
+        !anim->curve()->ToScrollOffsetAnimationCurve()->HasSetInitialValue()) {
+      gfx::ScrollOffset current_scroll_offset;
+      if (animation_ticker_impl->HasElementInActiveList()) {
+        current_scroll_offset =
+            animation_ticker_impl->ScrollOffsetForAnimation();
+      } else {
+        // The owning layer isn't yet in the active tree, so the main thread
+        // scroll offset will be up to date.
+        current_scroll_offset = ScrollOffsetForAnimation();
+      }
+      anim->curve()->ToScrollOffsetAnimationCurve()->SetInitialValue(
+          current_scroll_offset);
+    }
+
+    // The new animation should be set to run as soon as possible.
+    Animation::RunState initial_run_state =
+        Animation::WAITING_FOR_TARGET_AVAILABILITY;
+    std::unique_ptr<Animation> to_add(
+        anim->CloneAndInitialize(initial_run_state));
+    DCHECK(!to_add->needs_synchronized_start_time());
+    to_add->set_affects_active_elements(false);
+    animation_ticker_impl->AddAnimation(std::move(to_add));
+  }
+}
+
+namespace {
+bool IsCompleted(Animation* animation,
+                 const AnimationTicker* main_thread_ticker) {
+  if (animation->is_impl_only()) {
+    return (animation->run_state() == Animation::WAITING_FOR_DELETION);
+  } else {
+    Animation* main_thread_animation =
+        main_thread_ticker->GetAnimationById(animation->id());
+    return !main_thread_animation || main_thread_animation->is_finished();
+  }
+}
+}  // namespace
+
+void AnimationTicker::RemoveAnimationsCompletedOnMainThread(
+    AnimationTicker* animation_ticker_impl) const {
+  bool animation_completed = false;
+
+  // Animations removed on the main thread should no longer affect pending
+  // elements, and should stop affecting active elements after the next call
+  // to ActivateAnimations. If already WAITING_FOR_DELETION, they can be removed
+  // immediately.
+  auto& animations = animation_ticker_impl->animations_;
+  for (const auto& animation : animations) {
+    if (IsCompleted(animation.get(), this)) {
+      animation->set_affects_pending_elements(false);
+      animation_completed = true;
+    }
+  }
+  auto affects_active_only_and_is_waiting_for_deletion =
+      [](const std::unique_ptr<Animation>& animation) {
+        return animation->run_state() == Animation::WAITING_FOR_DELETION &&
+               !animation->affects_pending_elements();
+      };
+  base::EraseIf(animations, affects_active_only_and_is_waiting_for_deletion);
+
+  if (has_bound_element_animations() && animation_completed)
+    element_animations_->SetNeedsUpdateImplClientState();
+}
+
+void AnimationTicker::PushPropertiesToImplThread(
+    AnimationTicker* animation_ticker_impl) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    Animation* current_impl =
+        animation_ticker_impl->GetAnimationById(animations_[i]->id());
+    if (current_impl)
+      animations_[i]->PushPropertiesTo(current_impl);
+  }
+  animation_ticker_impl->scroll_offset_animation_was_interrupted_ =
+      scroll_offset_animation_was_interrupted_;
+  scroll_offset_animation_was_interrupted_ = false;
+}
+
+std::string AnimationTicker::AnimationsToString() const {
+  std::string str;
+  for (size_t i = 0; i < animations_.size(); i++) {
+    if (i > 0)
+      str.append(", ");
+    str.append(animations_[i]->ToString());
+  }
+  return str;
+}
+
+void AnimationTicker::StartAnimations(base::TimeTicks monotonic_time) {
+  DCHECK(needs_to_start_animations_);
+  needs_to_start_animations_ = false;
+
+  // First collect running properties affecting each type of element.
+  TargetProperties blocked_properties_for_active_elements;
+  TargetProperties blocked_properties_for_pending_elements;
+  std::vector<size_t> animations_waiting_for_target;
+
+  animations_waiting_for_target.reserve(animations_.size());
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() == Animation::STARTING ||
+        animations_[i]->run_state() == Animation::RUNNING) {
+      int property = animations_[i]->target_property_id();
+      if (animations_[i]->affects_active_elements()) {
+        blocked_properties_for_active_elements[property] = true;
+      }
+      if (animations_[i]->affects_pending_elements()) {
+        blocked_properties_for_pending_elements[property] = true;
+      }
+    } else if (animations_[i]->run_state() ==
+               Animation::WAITING_FOR_TARGET_AVAILABILITY) {
+      animations_waiting_for_target.push_back(i);
+    }
+  }
+
+  for (size_t i = 0; i < animations_waiting_for_target.size(); ++i) {
+    // Collect all properties for animations with the same group id (they
+    // should all also be in the list of animations).
+    size_t animation_index = animations_waiting_for_target[i];
+    Animation* animation_waiting_for_target =
+        animations_[animation_index].get();
+    // Check for the run state again even though the animation was waiting
+    // for target because it might have changed the run state while handling
+    // previous animation in this loop (if they belong to same group).
+    if (animation_waiting_for_target->run_state() ==
+        Animation::WAITING_FOR_TARGET_AVAILABILITY) {
+      TargetProperties enqueued_properties;
+      bool affects_active_elements =
+          animation_waiting_for_target->affects_active_elements();
+      bool affects_pending_elements =
+          animation_waiting_for_target->affects_pending_elements();
+      enqueued_properties[animation_waiting_for_target->target_property_id()] =
+          true;
+      for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
+        if (animation_waiting_for_target->group() == animations_[j]->group()) {
+          enqueued_properties[animations_[j]->target_property_id()] = true;
+          affects_active_elements |= animations_[j]->affects_active_elements();
+          affects_pending_elements |=
+              animations_[j]->affects_pending_elements();
+        }
+      }
+
+      // Check to see if intersection of the list of properties affected by
+      // the group and the list of currently blocked properties is null, taking
+      // into account the type(s) of elements affected by the group. In any
+      // case, the group's target properties need to be added to the lists of
+      // blocked properties.
+      bool null_intersection = true;
+      for (int property = TargetProperty::FIRST_TARGET_PROPERTY;
+           property <= TargetProperty::LAST_TARGET_PROPERTY; ++property) {
+        if (enqueued_properties[property]) {
+          if (affects_active_elements) {
+            if (blocked_properties_for_active_elements[property])
+              null_intersection = false;
+            else
+              blocked_properties_for_active_elements[property] = true;
+          }
+          if (affects_pending_elements) {
+            if (blocked_properties_for_pending_elements[property])
+              null_intersection = false;
+            else
+              blocked_properties_for_pending_elements[property] = true;
+          }
+        }
+      }
+
+      // If the intersection is null, then we are free to start the animations
+      // in the group.
+      if (null_intersection) {
+        animation_waiting_for_target->SetRunState(Animation::STARTING,
+                                                  monotonic_time);
+        for (size_t j = animation_index + 1; j < animations_.size(); ++j) {
+          if (animation_waiting_for_target->group() ==
+              animations_[j]->group()) {
+            animations_[j]->SetRunState(Animation::STARTING, monotonic_time);
+          }
+        }
+      } else {
+        needs_to_start_animations_ = true;
+      }
+    }
+  }
+}
+
+void AnimationTicker::PromoteStartedAnimations(AnimationEvents* events) {
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (animations_[i]->run_state() == Animation::STARTING &&
+        animations_[i]->affects_active_elements()) {
+      animations_[i]->SetRunState(Animation::RUNNING, last_tick_time_);
+      if (!animations_[i]->has_set_start_time() &&
+          !animations_[i]->needs_synchronized_start_time())
+        animations_[i]->set_start_time(last_tick_time_);
+      if (events) {
+        base::TimeTicks start_time;
+        if (animations_[i]->has_set_start_time())
+          start_time = animations_[i]->start_time();
+        else
+          start_time = last_tick_time_;
+        AnimationEvent started_event(
+            AnimationEvent::STARTED, element_id_, animations_[i]->group(),
+            animations_[i]->target_property_id(), start_time);
+        started_event.is_impl_only = animations_[i]->is_impl_only();
+        if (started_event.is_impl_only) {
+          // Notify delegate directly, do not record the event.
+          animation_player_->NotifyImplOnlyAnimationStarted(started_event);
+        } else {
+          events->events_.push_back(started_event);
+        }
+      }
+    }
+  }
+}
+
+void AnimationTicker::MarkAnimationsForDeletion(base::TimeTicks monotonic_time,
+                                                AnimationEvents* events) {
+  bool marked_animations_for_deletions = false;
+  std::vector<size_t> animations_with_same_group_id;
+
+  animations_with_same_group_id.reserve(animations_.size());
+  // Non-aborted animations are marked for deletion after a corresponding
+  // AnimationEvent::FINISHED event is sent or received. This means that if
+  // we don't have an events vector, we must ensure that non-aborted animations
+  // have received a finished event before marking them for deletion.
+  for (size_t i = 0; i < animations_.size(); i++) {
+    int group_id = animations_[i]->group();
+    if (animations_[i]->run_state() == Animation::ABORTED) {
+      if (events && !animations_[i]->is_impl_only()) {
+        AnimationEvent aborted_event(
+            AnimationEvent::ABORTED, element_id_, group_id,
+            animations_[i]->target_property_id(), monotonic_time);
+        events->events_.push_back(aborted_event);
+      }
+      // If on the compositor or on the main thread and received finish event,
+      // animation can be marked for deletion.
+      if (events || animations_[i]->received_finished_event()) {
+        animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
+                                    monotonic_time);
+        marked_animations_for_deletions = true;
+      }
+      continue;
+    }
+
+    // If running on the compositor and need to complete an aborted animation
+    // on the main thread.
+    if (events && animations_[i]->run_state() ==
+                      Animation::ABORTED_BUT_NEEDS_COMPLETION) {
+      AnimationEvent aborted_event(
+          AnimationEvent::TAKEOVER, element_id_, group_id,
+          animations_[i]->target_property_id(), monotonic_time);
+      aborted_event.animation_start_time = animations_[i]->start_time();
+      const ScrollOffsetAnimationCurve* scroll_offset_animation_curve =
+          animations_[i]->curve()->ToScrollOffsetAnimationCurve();
+      aborted_event.curve = scroll_offset_animation_curve->Clone();
+      // Notify the compositor that the animation is finished.
+      animation_player_->NotifyAnimationTakeoverByMain(aborted_event);
+      // Notify main thread.
+      events->events_.push_back(aborted_event);
+
+      // Remove the animation from the compositor.
+      animations_[i]->SetRunState(Animation::WAITING_FOR_DELETION,
+                                  monotonic_time);
+      marked_animations_for_deletions = true;
+      continue;
+    }
+
+    bool all_anims_with_same_id_are_finished = false;
+
+    // Since deleting an animation on the main thread leads to its deletion
+    // on the impl thread, we only mark a FINISHED main thread animation for
+    // deletion once it has received a FINISHED event from the impl thread.
+    bool animation_i_will_send_or_has_received_finish_event =
+        animations_[i]->is_controlling_instance() ||
+        animations_[i]->is_impl_only() ||
+        animations_[i]->received_finished_event();
+    // If an animation is finished, and not already marked for deletion,
+    // find out if all other animations in the same group are also finished.
+    if (animations_[i]->run_state() == Animation::FINISHED &&
+        animation_i_will_send_or_has_received_finish_event) {
+      // Clear the animations_with_same_group_id if it was added for
+      // the previous animation's iteration.
+      if (animations_with_same_group_id.size() > 0)
+        animations_with_same_group_id.clear();
+      all_anims_with_same_id_are_finished = true;
+      for (size_t j = 0; j < animations_.size(); ++j) {
+        bool animation_j_will_send_or_has_received_finish_event =
+            animations_[j]->is_controlling_instance() ||
+            animations_[j]->is_impl_only() ||
+            animations_[j]->received_finished_event();
+        if (group_id == animations_[j]->group()) {
+          if (!animations_[j]->is_finished() ||
+              (animations_[j]->run_state() == Animation::FINISHED &&
+               !animation_j_will_send_or_has_received_finish_event)) {
+            all_anims_with_same_id_are_finished = false;
+            break;
+          } else if (j >= i &&
+                     animations_[j]->run_state() != Animation::ABORTED) {
+            // Mark down the animations which belong to the same group
+            // and is not yet aborted. If this current iteration finds that all
+            // animations with same ID are finished, then the marked
+            // animations below will be set to WAITING_FOR_DELETION in next
+            // iteration.
+            animations_with_same_group_id.push_back(j);
+          }
+        }
+      }
+    }
+
+    if (all_anims_with_same_id_are_finished) {
+      // We now need to remove all animations with the same group id as
+      // group_id (and send along animation finished notifications, if
+      // necessary).
+      for (size_t j = 0; j < animations_with_same_group_id.size(); j++) {
+        size_t animation_index = animations_with_same_group_id[j];
+        if (events) {
+          AnimationEvent finished_event(
+              AnimationEvent::FINISHED, element_id_,
+              animations_[animation_index]->group(),
+              animations_[animation_index]->target_property_id(),
+              monotonic_time);
+          finished_event.is_impl_only =
+              animations_[animation_index]->is_impl_only();
+          if (finished_event.is_impl_only) {
+            // Notify delegate directly, do not record the event.
+            animation_player_->NotifyImplOnlyAnimationFinished(finished_event);
+          } else {
+            events->events_.push_back(finished_event);
+          }
+        }
+        animations_[animation_index]->SetRunState(
+            Animation::WAITING_FOR_DELETION, monotonic_time);
+      }
+      marked_animations_for_deletions = true;
+    }
+  }
+
+  // We need to purge animations marked for deletion, which happens in
+  // PushProperties().
+  if (marked_animations_for_deletions)
+    animation_player_->SetNeedsPushProperties();
+}
+
+void AnimationTicker::MarkFinishedAnimations(base::TimeTicks monotonic_time) {
+  DCHECK(has_bound_element_animations());
+
+  bool animation_finished = false;
+  for (size_t i = 0; i < animations_.size(); ++i) {
+    if (!animations_[i]->is_finished() &&
+        animations_[i]->IsFinishedAt(monotonic_time)) {
+      animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
+      animation_finished = true;
+      animation_player_->SetNeedsPushProperties();
+    }
+    if (!animations_[i]->affects_active_elements() &&
+        !animations_[i]->affects_pending_elements()) {
+      switch (animations_[i]->run_state()) {
+        case Animation::WAITING_FOR_TARGET_AVAILABILITY:
+        case Animation::STARTING:
+        case Animation::RUNNING:
+        case Animation::PAUSED:
+          animations_[i]->SetRunState(Animation::FINISHED, monotonic_time);
+          animation_finished = true;
+          break;
+        default:
+          break;
+      }
+    }
+  }
+  if (animation_finished)
+    element_animations_->UpdateClientAnimationState();
+}
+
+bool AnimationTicker::HasElementInActiveList() const {
+  DCHECK(has_bound_element_animations());
+  return element_animations_->has_element_in_active_list();
+}
+
+gfx::ScrollOffset AnimationTicker::ScrollOffsetForAnimation() const {
+  DCHECK(has_bound_element_animations());
+  return element_animations_->ScrollOffsetForAnimation();
+}
+
+}  // namespace cc
diff --git a/cc/animation/animation_ticker.h b/cc/animation/animation_ticker.h
new file mode 100644
index 0000000..a2007d34
--- /dev/null
+++ b/cc/animation/animation_ticker.h
@@ -0,0 +1,160 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CC_ANIMATION_ANIMATION_TICKER_H_
+#define CC_ANIMATION_ANIMATION_TICKER_H_
+
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/time/time.h"
+#include "cc/animation/animation_events.h"
+#include "cc/animation/animation_export.h"
+#include "cc/animation/element_animations.h"
+#include "cc/trees/element_id.h"
+#include "cc/trees/mutator_host_client.h"
+#include "cc/trees/target_property.h"
+#include "ui/gfx/geometry/box_f.h"
+#include "ui/gfx/geometry/scroll_offset.h"
+
+#include <memory>
+#include <vector>
+
+namespace cc {
+
+class Animation;
+class AnimationHost;
+class AnimationPlayer;
+struct PropertyAnimationState;
+
+// An AnimationTicker owns a group of Animations for a single target (identified
+// by a ElementId). It is responsible for managing the animations' running
+// states (starting, running, paused, etc), as well as ticking the animations
+// when it is requested to produce new outputs for a given time.
+//
+// Note that a single AnimationTicker may not own all the animations for a given
+// target. AnimationTicker is only a grouping mechanism for related animations.
+// The commonality between animations on the same target is found via
+// ElementAnimations - there is only one ElementAnimations for a given target.
+class CC_ANIMATION_EXPORT AnimationTicker {
+ public:
+  explicit AnimationTicker(AnimationPlayer* animation_player);
+  ~AnimationTicker();
+
+  // ElementAnimations object where this controller is listed.
+  scoped_refptr<ElementAnimations> element_animations() const {
+    return element_animations_;
+  }
+
+  bool has_bound_element_animations() const { return !!element_animations_; }
+
+  bool has_attached_element() const { return !!element_id_; }
+
+  ElementId element_id() const { return element_id_; }
+
+  bool has_any_animation() const { return !animations_.empty(); }
+
+  // When a scroll animation is removed on the main thread, its compositor
+  // thread counterpart continues producing scroll deltas until activation.
+  // These scroll deltas need to be cleared at activation, so that the active
+  // element's scroll offset matches the offset provided by the main thread
+  // rather than a combination of this offset and scroll deltas produced by the
+  // removed animation. This is to provide the illusion of synchronicity to JS
+  // that simultaneously removes an animation and sets the scroll offset.
+  bool scroll_offset_animation_was_interrupted() const {
+    return scroll_offset_animation_was_interrupted_;
+  }
+
+  void BindElementAnimations(AnimationHost* animation_host);
+  void UnbindElementAnimations();
+
+  void AttachElement(ElementId element_id);
+  void DetachElement();
+
+  void Tick(base::TimeTicks monotonic_time);
+  static void TickAnimation(base::TimeTicks monotonic_time,
+                            Animation* animation,
+                            AnimationTarget* target);
+  void RemoveFromTicking();
+
+  void UpdateState(bool start_ready_animations, AnimationEvents* events);
+  void UpdateTickingState(UpdateTickingType type);
+
+  void AddAnimation(std::unique_ptr<Animation> animation);
+  void PauseAnimation(int animation_id, double time_offset);
+  void RemoveAnimation(int animation_id);
+  void AbortAnimation(int animation_id);
+  void AbortAnimations(TargetProperty::Type target_property,
+                       bool needs_completion);
+
+  void ActivateAnimations();
+
+  void AnimationAdded();
+
+  bool NotifyAnimationStarted(const AnimationEvent& event);
+  bool NotifyAnimationFinished(const AnimationEvent& event);
+  bool NotifyAnimationAborted(const AnimationEvent& event);
+
+  bool HasTickingAnimation() const;
+  bool HasNonDeletedAnimation() const;
+
+  bool HasOnlyTranslationTransforms(ElementListType list_type) const;
+
+  bool AnimationsPreserveAxisAlignment() const;
+
+  bool AnimationStartScale(ElementListType, float* start_scale) const;
+  bool MaximumTargetScale(ElementListType, float* max_scale) const;
+
+  bool IsPotentiallyAnimatingProperty(TargetProperty::Type target_property,
+                                      ElementListType list_type) const;
+  bool IsCurrentlyAnimatingProperty(TargetProperty::Type target_property,
+                                    ElementListType list_type) const;
+
+  Animation* GetAnimation(TargetProperty::Type target_property) const;
+  Animation* GetAnimationById(int animation_id) const;
+
+  void GetPropertyAnimationState(PropertyAnimationState* pending_state,
+                                 PropertyAnimationState* active_state) const;
+
+  void MarkAbortedAnimationsForDeletion(AnimationTicker* element_ticker_impl);
+  void PurgeAnimationsMarkedForDeletion(bool impl_only);
+  void PushNewAnimationsToImplThread(
+      AnimationTicker* element_ticker_impl) const;
+  void RemoveAnimationsCompletedOnMainThread(
+      AnimationTicker* element_ticker_impl) const;
+  void PushPropertiesToImplThread(AnimationTicker* element_ticker_impl);
+
+  std::string AnimationsToString() const;
+
+ private:
+  void StartAnimations(base::TimeTicks monotonic_time);
+  void PromoteStartedAnimations(AnimationEvents* events);
+
+  void MarkAnimationsForDeletion(base::TimeTicks, AnimationEvents* events);
+  void MarkFinishedAnimations(base::TimeTicks monotonic_time);
+
+  bool HasElementInActiveList() const;
+  gfx::ScrollOffset ScrollOffsetForAnimation() const;
+
+  std::vector<std::unique_ptr<Animation>> animations_;
+  AnimationPlayer* animation_player_;
+  ElementId element_id_;
+
+  // element_animations_ is non-null if controller is attached to an element.
+  scoped_refptr<ElementAnimations> element_animations_;
+
+  // Only try to start animations when new animations are added or when the
+  // previous attempt at starting animations failed to start all animations.
+  bool needs_to_start_animations_;
+
+  bool scroll_offset_animation_was_interrupted_;
+
+  bool is_ticking_;
+  base::TimeTicks last_tick_time_;
+
+  DISALLOW_COPY_AND_ASSIGN(AnimationTicker);
+};
+
+}  // namespace cc
+
+#endif  // CC_ANIMATION_ANIMATION_TICKER_H_
diff --git a/cc/animation/element_animations_unittest.cc b/cc/animation/element_animations_unittest.cc
index 620ee137..b437932a 100644
--- a/cc/animation/element_animations_unittest.cc
+++ b/cc/animation/element_animations_unittest.cc
@@ -208,17 +208,17 @@
   AttachTimelinePlayerLayer();
   CreateImplTimelineAndPlayer();
 
+  EXPECT_FALSE(player_->GetAnimation(TargetProperty::OPACITY));
   EXPECT_FALSE(player_impl_->GetAnimation(TargetProperty::OPACITY));
 
-  EXPECT_FALSE(player_->needs_to_start_animations());
-  EXPECT_FALSE(player_impl_->needs_to_start_animations());
-
   int animation_id =
       AddOpacityTransitionToPlayer(player_.get(), 1, 0, 1, false);
-  EXPECT_TRUE(player_->needs_to_start_animations());
+  EXPECT_TRUE(player_->GetAnimationById(animation_id));
+  EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+            player_->GetAnimationById(animation_id)->run_state());
+  EXPECT_FALSE(player_impl_->GetAnimationById(animation_id));
 
   PushProperties();
-  EXPECT_TRUE(player_impl_->needs_to_start_animations());
   player_impl_->ActivateAnimations();
 
   EXPECT_TRUE(player_impl_->GetAnimationById(animation_id));
@@ -232,11 +232,9 @@
   AttachTimelinePlayerLayer();
   CreateImplTimelineAndPlayer();
 
+  EXPECT_FALSE(player_->GetAnimation(TargetProperty::SCROLL_OFFSET));
   EXPECT_FALSE(player_impl_->GetAnimation(TargetProperty::SCROLL_OFFSET));
 
-  EXPECT_FALSE(player_->needs_to_start_animations());
-  EXPECT_FALSE(player_impl_->needs_to_start_animations());
-
   gfx::ScrollOffset initial_value(100.f, 300.f);
   gfx::ScrollOffset provider_initial_value(150.f, 300.f);
   gfx::ScrollOffset target_value(300.f, 200.f);
@@ -695,12 +693,16 @@
   std::unique_ptr<Animation> to_add(CreateAnimation(
       std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
       1, TargetProperty::OPACITY));
+  int animation_id = to_add->id();
 
-  EXPECT_FALSE(player_->needs_to_start_animations());
+  EXPECT_FALSE(player_->GetAnimationById(animation_id));
   player_->AddAnimation(std::move(to_add));
-  EXPECT_TRUE(player_->needs_to_start_animations());
+  EXPECT_TRUE(player_->GetAnimationById(animation_id));
+  EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+            player_->GetAnimationById(animation_id)->run_state());
   player_->Tick(kInitialTickTime);
-  EXPECT_FALSE(player_->needs_to_start_animations());
+  EXPECT_EQ(Animation::STARTING,
+            player_->GetAnimationById(animation_id)->run_state());
   player_->UpdateState(true, events.get());
   EXPECT_TRUE(player_->HasTickingAnimation());
   EXPECT_EQ(0.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE));
@@ -1219,30 +1221,41 @@
 
   auto events = CreateEventsForTesting();
 
-  EXPECT_FALSE(player_->needs_to_start_animations());
-
-  player_->AddAnimation(CreateAnimation(
+  int animation1_id = 1;
+  int animation2_id = 2;
+  player_->AddAnimation(Animation::Create(
       std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)),
-      1, TargetProperty::OPACITY));
-  player_->AddAnimation(CreateAnimation(
+      animation1_id, 1, TargetProperty::OPACITY));
+  player_->AddAnimation(Animation::Create(
       std::unique_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 1.f, 0.5f)),
-      2, TargetProperty::OPACITY));
-
-  EXPECT_TRUE(player_->needs_to_start_animations());
+      animation2_id, 2, TargetProperty::OPACITY));
 
   player_->Tick(kInitialTickTime);
 
+  // The first animation should have been started.
+  EXPECT_TRUE(player_->GetAnimationById(animation1_id));
+  EXPECT_EQ(Animation::STARTING,
+            player_->GetAnimationById(animation1_id)->run_state());
+
   // The second animation still needs to be started.
-  EXPECT_TRUE(player_->needs_to_start_animations());
+  EXPECT_TRUE(player_->GetAnimationById(animation2_id));
+  EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
+            player_->GetAnimationById(animation2_id)->run_state());
 
   player_->UpdateState(true, events.get());
   EXPECT_TRUE(player_->HasTickingAnimation());
   EXPECT_EQ(0.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE));
 
   player_->Tick(kInitialTickTime + TimeDelta::FromMilliseconds(1000));
-  EXPECT_TRUE(player_->needs_to_start_animations());
   player_->UpdateState(true, events.get());
-  EXPECT_FALSE(player_->needs_to_start_animations());
+
+  // Now the first should be finished, and the second started.
+  EXPECT_TRUE(player_->GetAnimationById(animation1_id));
+  EXPECT_EQ(Animation::FINISHED,
+            player_->GetAnimationById(animation1_id)->run_state());
+  EXPECT_TRUE(player_->GetAnimationById(animation2_id));
+  EXPECT_EQ(Animation::RUNNING,
+            player_->GetAnimationById(animation2_id)->run_state());
 
   EXPECT_TRUE(player_->HasTickingAnimation());
   EXPECT_EQ(1.f, client_.GetOpacity(element_id_, ElementListType::ACTIVE));
@@ -2381,14 +2394,12 @@
 
   auto events = CreateEventsForTesting();
 
-  EXPECT_FALSE(player_->needs_to_start_animations());
   int animation_id =
       AddOpacityTransitionToPlayer(player_.get(), 1, 0.5f, 1.f, false);
-  EXPECT_TRUE(player_->needs_to_start_animations());
+  EXPECT_TRUE(player_->GetAnimationById(animation_id));
+  EXPECT_FALSE(player_impl_->GetAnimationById(animation_id));
 
-  EXPECT_FALSE(player_impl_->needs_to_start_animations());
   PushProperties();
-  EXPECT_TRUE(player_impl_->needs_to_start_animations());
 
   EXPECT_TRUE(player_impl_->GetAnimationById(animation_id));
   EXPECT_EQ(Animation::WAITING_FOR_TARGET_AVAILABILITY,
@@ -2399,7 +2410,8 @@
       player_impl_->GetAnimationById(animation_id)->affects_active_elements());
 
   player_impl_->Tick(kInitialTickTime);
-  EXPECT_FALSE(player_impl_->needs_to_start_animations());
+  EXPECT_EQ(Animation::STARTING,
+            player_impl_->GetAnimationById(animation_id)->run_state());
   player_impl_->UpdateState(true, events.get());
 
   // Since the animation hasn't been activated, it should still be STARTING
diff --git a/cc/ipc/BUILD.gn b/cc/ipc/BUILD.gn
index 47a1a3f..e59f265 100644
--- a/cc/ipc/BUILD.gn
+++ b/cc/ipc/BUILD.gn
@@ -36,31 +36,3 @@
     "//ui/latency/ipc",
   ]
 }
-
-mojom("interfaces") {
-  sources = [
-    "copy_output_result.mojom",
-    "texture_mailbox.mojom",
-    "texture_mailbox_releaser.mojom",
-  ]
-
-  public_deps = [
-    "//gpu/ipc/common:interfaces",
-    "//mojo/common:common_custom_types",
-    "//skia/public/interfaces",
-    "//ui/gfx/geometry/mojo",
-    "//ui/gfx/mojo",
-    "//ui/latency/mojo:interfaces",
-  ]
-}
-
-mojom("test_interfaces") {
-  testonly = true
-  sources = [
-    "traits_test_service.mojom",
-  ]
-
-  public_deps = [
-    ":interfaces",
-  ]
-}
diff --git a/cc/ipc/cc_param_traits.cc b/cc/ipc/cc_param_traits.cc
index 2f45cd0..b5313ac4 100644
--- a/cc/ipc/cc_param_traits.cc
+++ b/cc/ipc/cc_param_traits.cc
@@ -14,13 +14,13 @@
 #include "cc/base/filter_operations.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/largest_draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "third_party/skia/include/core/SkData.h"
 #include "third_party/skia/include/core/SkFlattenableSerialization.h"
@@ -333,34 +333,34 @@
         << " visible_rect: " << quad->visible_rect.ToString();
 
     switch (quad->material) {
-      case cc::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         WriteParam(m, *cc::DebugBorderDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         NOTREACHED();
         break;
-      case cc::DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         WriteParam(m, *cc::TextureDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         WriteParam(m, *cc::RenderPassDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         WriteParam(m, *cc::SolidColorDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         WriteParam(m, *cc::SurfaceDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         WriteParam(m, *cc::TileDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         WriteParam(m, *cc::StreamVideoDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         WriteParam(m, *cc::YUVVideoDrawQuad::MaterialCast(quad));
         break;
-      case cc::DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
 
@@ -408,9 +408,9 @@
 }
 
 template <typename QuadType>
-static cc::DrawQuad* ReadDrawQuad(const base::Pickle* m,
-                                  base::PickleIterator* iter,
-                                  cc::RenderPass* render_pass) {
+static viz::DrawQuad* ReadDrawQuad(const base::Pickle* m,
+                                   base::PickleIterator* iter,
+                                   cc::RenderPass* render_pass) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
                "ParamTraits::ReadDrawQuad");
   QuadType* quad = render_pass->CreateAndAppendDrawQuad<QuadType>();
@@ -453,43 +453,43 @@
             background_filters, color_space, has_transparent_background,
             cache_render_pass, has_damage_from_contributing_content);
 
-  cc::DrawQuad* last_draw_quad = nullptr;
+  viz::DrawQuad* last_draw_quad = nullptr;
   for (uint32_t i = 0; i < quad_list_size; ++i) {
-    cc::DrawQuad::Material material;
+    viz::DrawQuad::Material material;
     base::PickleIterator temp_iter = *iter;
     if (!ReadParam(m, &temp_iter, &material))
       return false;
 
-    cc::DrawQuad* draw_quad = nullptr;
+    viz::DrawQuad* draw_quad = nullptr;
     switch (material) {
-      case cc::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         draw_quad = ReadDrawQuad<cc::DebugBorderDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         NOTREACHED();
         return false;
-      case cc::DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         draw_quad = ReadDrawQuad<cc::SurfaceDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         draw_quad = ReadDrawQuad<cc::TextureDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         draw_quad = ReadDrawQuad<cc::RenderPassDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         draw_quad = ReadDrawQuad<cc::SolidColorDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         draw_quad = ReadDrawQuad<cc::TileDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         draw_quad = ReadDrawQuad<cc::StreamVideoDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         draw_quad = ReadDrawQuad<cc::YUVVideoDrawQuad>(m, iter, p);
         break;
-      case cc::DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
     if (!draw_quad)
@@ -515,14 +515,14 @@
     draw_quad->shared_quad_state = p->shared_quad_state_list.back();
     // If this quad is a fallback SurfaceDrawQuad then update the previous
     // primary SurfaceDrawQuad to point to this quad.
-    if (draw_quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+    if (draw_quad->material == viz::DrawQuad::SURFACE_CONTENT) {
       const cc::SurfaceDrawQuad* surface_draw_quad =
           cc::SurfaceDrawQuad::MaterialCast(draw_quad);
       if (surface_draw_quad->surface_draw_quad_type ==
           cc::SurfaceDrawQuadType::FALLBACK) {
         // A fallback quad must immediately follow a primary SurfaceDrawQuad.
         if (!last_draw_quad ||
-            last_draw_quad->material != cc::DrawQuad::SURFACE_CONTENT) {
+            last_draw_quad->material != viz::DrawQuad::SURFACE_CONTENT) {
           return false;
         }
         cc::SurfaceDrawQuad* last_surface_draw_quad =
@@ -575,34 +575,34 @@
     if (quad != p.quad_list.front())
       l->append(", ");
     switch (quad->material) {
-      case cc::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         LogParam(*cc::DebugBorderDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         NOTREACHED();
         break;
-      case cc::DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         LogParam(*cc::TextureDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         LogParam(*cc::RenderPassDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         LogParam(*cc::SolidColorDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         LogParam(*cc::SurfaceDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         LogParam(*cc::TileDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         LogParam(*cc::StreamVideoDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         LogParam(*cc::YUVVideoDrawQuad::MaterialCast(quad), l);
         break;
-      case cc::DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
   }
@@ -790,7 +790,7 @@
     // Validate that each RenderPassDrawQuad points at a valid RenderPass
     // earlier in the frame.
     for (const auto* quad : render_pass->quad_list) {
-      if (quad->material != cc::DrawQuad::RENDER_PASS)
+      if (quad->material != viz::DrawQuad::RENDER_PASS)
         continue;
       const cc::RenderPassDrawQuad* rpdq =
           cc::RenderPassDrawQuad::MaterialCast(quad);
@@ -819,24 +819,24 @@
   l->append("])");
 }
 
-void ParamTraits<cc::DrawQuad::Resources>::Write(base::Pickle* m,
-                                                 const param_type& p) {
+void ParamTraits<viz::DrawQuad::Resources>::Write(base::Pickle* m,
+                                                  const param_type& p) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
                "ParamTraits::DrawQuad::Resources::Write");
-  DCHECK_LE(p.count, cc::DrawQuad::Resources::kMaxResourceIdCount);
+  DCHECK_LE(p.count, viz::DrawQuad::Resources::kMaxResourceIdCount);
   WriteParam(m, p.count);
   for (size_t i = 0; i < p.count; ++i)
     WriteParam(m, p.ids[i]);
 }
 
-bool ParamTraits<cc::DrawQuad::Resources>::Read(const base::Pickle* m,
-                                                base::PickleIterator* iter,
-                                                param_type* p) {
+bool ParamTraits<viz::DrawQuad::Resources>::Read(const base::Pickle* m,
+                                                 base::PickleIterator* iter,
+                                                 param_type* p) {
   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug.ipc"),
                "ParamTraits::DrawQuad::Resources::Read");
   if (!ReadParam(m, iter, &p->count))
     return false;
-  if (p->count > cc::DrawQuad::Resources::kMaxResourceIdCount)
+  if (p->count > viz::DrawQuad::Resources::kMaxResourceIdCount)
     return false;
   for (size_t i = 0; i < p->count; ++i) {
     if (!ReadParam(m, iter, &p->ids[i]))
@@ -845,12 +845,12 @@
   return true;
 }
 
-void ParamTraits<cc::DrawQuad::Resources>::Log(const param_type& p,
-                                               std::string* l) {
+void ParamTraits<viz::DrawQuad::Resources>::Log(const param_type& p,
+                                                std::string* l) {
   l->append("DrawQuad::Resources(");
   LogParam(p.count, l);
   l->append(", [");
-  if (p.count > cc::DrawQuad::Resources::kMaxResourceIdCount) {
+  if (p.count > viz::DrawQuad::Resources::kMaxResourceIdCount) {
     l->append("])");
     return;
   }
@@ -865,7 +865,7 @@
 
 void ParamTraits<cc::YUVVideoDrawQuad>::Write(base::Pickle* m,
                                               const param_type& p) {
-  ParamTraits<cc::DrawQuad>::Write(m, p);
+  ParamTraits<viz::DrawQuad>::Write(m, p);
   WriteParam(m, p.ya_tex_coord_rect);
   WriteParam(m, p.uv_tex_coord_rect);
   WriteParam(m, p.ya_tex_size);
@@ -880,7 +880,7 @@
 bool ParamTraits<cc::YUVVideoDrawQuad>::Read(const base::Pickle* m,
                                              base::PickleIterator* iter,
                                              param_type* p) {
-  return ParamTraits<cc::DrawQuad>::Read(m, iter, p) &&
+  return ParamTraits<viz::DrawQuad>::Read(m, iter, p) &&
          ReadParam(m, iter, &p->ya_tex_coord_rect) &&
          ReadParam(m, iter, &p->uv_tex_coord_rect) &&
          ReadParam(m, iter, &p->ya_tex_size) &&
@@ -897,7 +897,7 @@
 void ParamTraits<cc::YUVVideoDrawQuad>::Log(const param_type& p,
                                             std::string* l) {
   l->append("(");
-  ParamTraits<cc::DrawQuad>::Log(p, l);
+  ParamTraits<viz::DrawQuad>::Log(p, l);
   l->append(", ");
   LogParam(p.ya_tex_coord_rect, l);
   l->append(", ");
diff --git a/cc/ipc/cc_param_traits.h b/cc/ipc/cc_param_traits.h
index 2c87073..18b7a2658 100644
--- a/cc/ipc/cc_param_traits.h
+++ b/cc/ipc/cc_param_traits.h
@@ -11,9 +11,9 @@
 #include "cc/ipc/cc_ipc_export.h"
 #include "cc/ipc/cc_param_traits_macros.h"
 #include "cc/output/compositor_frame.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/stream_video_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "gpu/ipc/common/gpu_command_buffer_traits.h"
 #include "ipc/ipc_message_macros.h"
 
@@ -114,8 +114,8 @@
 };
 
 template <>
-struct CC_IPC_EXPORT ParamTraits<cc::DrawQuad::Resources> {
-  typedef cc::DrawQuad::Resources param_type;
+struct CC_IPC_EXPORT ParamTraits<viz::DrawQuad::Resources> {
+  typedef viz::DrawQuad::Resources param_type;
   static void Write(base::Pickle* m, const param_type& p);
   static bool Read(const base::Pickle* m,
                    base::PickleIterator* iter,
diff --git a/cc/ipc/cc_param_traits_macros.h b/cc/ipc/cc_param_traits_macros.h
index 4192e3c..1337c6c8 100644
--- a/cc/ipc/cc_param_traits_macros.h
+++ b/cc/ipc/cc_param_traits_macros.h
@@ -8,7 +8,6 @@
 #include "cc/base/filter_operation.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/stream_video_draw_quad.h"
@@ -17,6 +16,7 @@
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "components/viz/common/resources/returned_resource.h"
 #include "components/viz/common/resources/transferable_resource.h"
@@ -31,7 +31,7 @@
 #undef IPC_MESSAGE_EXPORT
 #define IPC_MESSAGE_EXPORT CC_IPC_EXPORT
 
-IPC_ENUM_TRAITS_MAX_VALUE(cc::DrawQuad::Material, cc::DrawQuad::MATERIAL_LAST)
+IPC_ENUM_TRAITS_MAX_VALUE(viz::DrawQuad::Material, viz::DrawQuad::MATERIAL_LAST)
 IPC_ENUM_TRAITS_MAX_VALUE(cc::FilterOperation::FilterType,
                           cc::FilterOperation::FILTER_TYPE_LAST)
 // TODO(wutao): This trait belongs with skia code.
@@ -51,7 +51,7 @@
   IPC_STRUCT_TRAITS_MEMBER(sequence)
 IPC_STRUCT_TRAITS_END()
 
-IPC_STRUCT_TRAITS_BEGIN(cc::DrawQuad)
+IPC_STRUCT_TRAITS_BEGIN(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(material)
   IPC_STRUCT_TRAITS_MEMBER(rect)
   IPC_STRUCT_TRAITS_MEMBER(visible_rect)
@@ -60,13 +60,13 @@
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::DebugBorderDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(color)
   IPC_STRUCT_TRAITS_MEMBER(width)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::RenderPassDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(render_pass_id)
   IPC_STRUCT_TRAITS_MEMBER(mask_uv_rect)
   IPC_STRUCT_TRAITS_MEMBER(mask_texture_size)
@@ -76,13 +76,13 @@
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::SolidColorDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(color)
   IPC_STRUCT_TRAITS_MEMBER(force_anti_aliasing_off)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::StreamVideoDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(overlay_resources)
   IPC_STRUCT_TRAITS_MEMBER(matrix)
 IPC_STRUCT_TRAITS_END()
@@ -92,13 +92,13 @@
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::SurfaceDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(surface_id)
   IPC_STRUCT_TRAITS_MEMBER(surface_draw_quad_type)
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::TextureDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(overlay_resources)
   IPC_STRUCT_TRAITS_MEMBER(premultiplied_alpha)
   IPC_STRUCT_TRAITS_MEMBER(uv_top_left)
@@ -118,7 +118,7 @@
 IPC_STRUCT_TRAITS_END()
 
 IPC_STRUCT_TRAITS_BEGIN(cc::TileDrawQuad)
-  IPC_STRUCT_TRAITS_PARENT(cc::DrawQuad)
+  IPC_STRUCT_TRAITS_PARENT(viz::DrawQuad)
   IPC_STRUCT_TRAITS_MEMBER(tex_coord_rect)
   IPC_STRUCT_TRAITS_MEMBER(texture_size)
   IPC_STRUCT_TRAITS_MEMBER(swizzle_contents)
diff --git a/cc/ipc/cc_param_traits_unittest.cc b/cc/ipc/cc_param_traits_unittest.cc
index e686df07..916bede9 100644
--- a/cc/ipc/cc_param_traits_unittest.cc
+++ b/cc/ipc/cc_param_traits_unittest.cc
@@ -23,7 +23,7 @@
 
 using cc::CompositorFrame;
 using cc::DebugBorderDrawQuad;
-using cc::DrawQuad;
+using viz::DrawQuad;
 using cc::FilterOperation;
 using cc::FilterOperations;
 using cc::PictureDrawQuad;
@@ -90,8 +90,8 @@
     EXPECT_EQ(a->sorting_context_id, b->sorting_context_id);
   }
 
-  void Compare(const DrawQuad* a, const DrawQuad* b) {
-    ASSERT_NE(DrawQuad::INVALID, a->material);
+  void Compare(const viz::DrawQuad* a, const viz::DrawQuad* b) {
+    ASSERT_NE(viz::DrawQuad::INVALID, a->material);
     ASSERT_EQ(a->material, b->material);
     EXPECT_EQ(a->rect.ToString(), b->rect.ToString());
     EXPECT_EQ(a->visible_rect.ToString(), b->visible_rect.ToString());
@@ -100,42 +100,42 @@
     Compare(a->shared_quad_state, b->shared_quad_state);
 
     switch (a->material) {
-      case DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         Compare(DebugBorderDrawQuad::MaterialCast(a),
                 DebugBorderDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         Compare(PictureDrawQuad::MaterialCast(a),
                 PictureDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         Compare(RenderPassDrawQuad::MaterialCast(a),
                 RenderPassDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         Compare(TextureDrawQuad::MaterialCast(a),
                 TextureDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         Compare(TileDrawQuad::MaterialCast(a), TileDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         Compare(SolidColorDrawQuad::MaterialCast(a),
                 SolidColorDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         Compare(StreamVideoDrawQuad::MaterialCast(a),
                 StreamVideoDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         Compare(SurfaceDrawQuad::MaterialCast(a),
                 SurfaceDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         Compare(YUVVideoDrawQuad::MaterialCast(a),
                 YUVVideoDrawQuad::MaterialCast(b));
         break;
-      case DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
   }
diff --git a/cc/ipc/copy_output_result.typemap b/cc/ipc/copy_output_result.typemap
deleted file mode 100644
index 39aa840..0000000
--- a/cc/ipc/copy_output_result.typemap
+++ /dev/null
@@ -1,16 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//cc/ipc/copy_output_result.mojom"
-public_headers = [ "//components/viz/common/quads/copy_output_result.h" ]
-traits_headers = [ "//cc/ipc/copy_output_result_struct_traits.h" ]
-public_deps = [
-  "//cc",
-  "//components/viz/common",
-  "//skia/public/interfaces:struct_traits",
-]
-sources = [
-  "copy_output_result_struct_traits.cc",
-]
-type_mappings = [ "cc.mojom.CopyOutputResult=std::unique_ptr<viz::CopyOutputResult>[move_only]" ]
diff --git a/cc/ipc/struct_traits_unittest.cc b/cc/ipc/struct_traits_unittest.cc
deleted file mode 100644
index ecae5d38..0000000
--- a/cc/ipc/struct_traits_unittest.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include <utility>
-
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "cc/input/selection.h"
-#include "cc/ipc/traits_test_service.mojom.h"
-#include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/render_pass.h"
-#include "cc/quads/render_pass_draw_quad.h"
-#include "cc/quads/solid_color_draw_quad.h"
-#include "cc/quads/stream_video_draw_quad.h"
-#include "cc/quads/surface_draw_quad.h"
-#include "cc/quads/texture_draw_quad.h"
-#include "cc/quads/yuv_video_draw_quad.h"
-#include "components/viz/common/quads/copy_output_result.h"
-#include "components/viz/test/begin_frame_args_test.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/skia/include/core/SkString.h"
-#include "third_party/skia/include/effects/SkDropShadowImageFilter.h"
-
-namespace cc {
-
-namespace {
-
-class StructTraitsTest : public testing::Test, public mojom::TraitsTestService {
- public:
-  StructTraitsTest() {}
-
- protected:
-  mojom::TraitsTestServicePtr GetTraitsTestProxy() {
-    mojom::TraitsTestServicePtr proxy;
-    traits_test_bindings_.AddBinding(this, mojo::MakeRequest(&proxy));
-    return proxy;
-  }
-
- private:
-  // TraitsTestService:
-  void EchoCopyOutputResult(std::unique_ptr<viz::CopyOutputResult> c,
-                            EchoCopyOutputResultCallback callback) override {
-    std::move(callback).Run(std::move(c));
-  }
-
-  void EchoTextureMailbox(const viz::TextureMailbox& t,
-                          EchoTextureMailboxCallback callback) override {
-    std::move(callback).Run(t);
-  }
-
-  mojo::BindingSet<TraitsTestService> traits_test_bindings_;
-  DISALLOW_COPY_AND_ASSIGN(StructTraitsTest);
-};
-
-}  // namespace
-
-TEST_F(StructTraitsTest, CopyOutputResult_Empty) {
-  auto input = std::make_unique<viz::CopyOutputResult>(
-      viz::CopyOutputResult::Format::RGBA_BITMAP, gfx::Rect());
-
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  std::unique_ptr<viz::CopyOutputResult> output;
-  proxy->EchoCopyOutputResult(std::move(input), &output);
-
-  EXPECT_TRUE(output->IsEmpty());
-  EXPECT_EQ(output->format(), viz::CopyOutputResult::Format::RGBA_BITMAP);
-  EXPECT_TRUE(output->rect().IsEmpty());
-  EXPECT_FALSE(output->AsSkBitmap().readyToDraw());
-  EXPECT_EQ(output->GetTextureMailbox(), nullptr);
-}
-
-TEST_F(StructTraitsTest, CopyOutputResult_Bitmap) {
-  const gfx::Rect result_rect(42, 43, 7, 8);
-  SkBitmap bitmap;
-  const sk_sp<SkColorSpace> adobe_rgb = SkColorSpace::MakeRGB(
-      SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kAdobeRGB_Gamut);
-  bitmap.allocN32Pixels(7, 8, adobe_rgb);
-  bitmap.eraseARGB(123, 213, 77, 33);
-  auto input =
-      std::make_unique<viz::CopyOutputSkBitmapResult>(result_rect, bitmap);
-
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  std::unique_ptr<viz::CopyOutputResult> output;
-  proxy->EchoCopyOutputResult(std::move(input), &output);
-
-  EXPECT_FALSE(output->IsEmpty());
-  EXPECT_EQ(output->format(), viz::CopyOutputResult::Format::RGBA_BITMAP);
-  EXPECT_EQ(output->rect(), result_rect);
-  EXPECT_EQ(output->GetTextureMailbox(), nullptr);
-
-  const SkBitmap& out_bitmap = output->AsSkBitmap();
-  EXPECT_TRUE(out_bitmap.readyToDraw());
-  EXPECT_EQ(out_bitmap.width(), result_rect.width());
-  EXPECT_EQ(out_bitmap.height(), result_rect.height());
-
-  // Check that the pixels are the same as the input and the color spaces are
-  // equivalent.
-  SkBitmap expected_bitmap;
-  expected_bitmap.allocN32Pixels(7, 8, adobe_rgb);
-  expected_bitmap.eraseARGB(123, 213, 77, 33);
-  EXPECT_EQ(expected_bitmap.getSize(), out_bitmap.getSize());
-  EXPECT_EQ(0, std::memcmp(expected_bitmap.getPixels(), out_bitmap.getPixels(),
-                           expected_bitmap.getSize()));
-  EXPECT_TRUE(SkColorSpace::Equals(expected_bitmap.colorSpace(),
-                                   out_bitmap.colorSpace()));
-}
-
-TEST_F(StructTraitsTest, CopyOutputResult_Texture) {
-  const gfx::Rect result_rect(12, 34, 56, 78);
-  const int8_t mailbox_name[GL_MAILBOX_SIZE_CHROMIUM] = {
-      0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 9, 7, 5, 3, 1, 3};
-  const uint32_t target = 3;
-  gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
-                            gpu::CommandBufferId::FromUnsafeValue(0x123),
-                            71234838);
-  base::RunLoop run_loop;
-  auto callback = viz::SingleReleaseCallback::Create(base::Bind(
-      [](base::Closure quit_closure, const gpu::SyncToken& expected_sync_token,
-         const gpu::SyncToken& sync_token, bool is_lost) {
-        EXPECT_EQ(expected_sync_token, sync_token);
-        EXPECT_TRUE(is_lost);
-        quit_closure.Run();
-      },
-      run_loop.QuitClosure(), sync_token));
-  gpu::Mailbox mailbox;
-  mailbox.SetName(mailbox_name);
-  viz::TextureMailbox texture_mailbox(mailbox, gpu::SyncToken(), target);
-  auto input = std::make_unique<viz::CopyOutputTextureResult>(
-      result_rect, texture_mailbox, std::move(callback));
-
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  std::unique_ptr<viz::CopyOutputResult> output;
-  proxy->EchoCopyOutputResult(std::move(input), &output);
-
-  EXPECT_FALSE(output->IsEmpty());
-  EXPECT_EQ(output->format(), viz::CopyOutputResult::Format::RGBA_TEXTURE);
-  EXPECT_EQ(output->rect(), result_rect);
-  ASSERT_NE(output->GetTextureMailbox(), nullptr);
-  EXPECT_EQ(output->GetTextureMailbox()->mailbox(), mailbox);
-
-  std::unique_ptr<viz::SingleReleaseCallback> out_callback =
-      output->TakeTextureOwnership();
-  out_callback->Run(sync_token, true /* is_lost */);
-  // If the CopyOutputResult callback is called (which is the intended
-  // behaviour), this will exit. Otherwise, this test will time out and fail.
-  run_loop.Run();
-}
-
-TEST_F(StructTraitsTest, TextureMailbox) {
-  const int8_t mailbox_name[GL_MAILBOX_SIZE_CHROMIUM] = {
-      0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 9, 7, 5, 3, 1, 2};
-  const gpu::CommandBufferNamespace command_buffer_namespace = gpu::IN_PROCESS;
-  const int32_t extra_data_field = 0xbeefbeef;
-  const gpu::CommandBufferId command_buffer_id(
-      gpu::CommandBufferId::FromUnsafeValue(0xdeadbeef));
-  const uint64_t release_count = 0xdeadbeefdeadL;
-  const gpu::SyncToken sync_token(command_buffer_namespace, extra_data_field,
-                                  command_buffer_id, release_count);
-  const uint32_t texture_target = 1337;
-  const gfx::Size size_in_pixels(93, 24);
-  const bool is_overlay_candidate = true;
-  const bool secure_output_only = true;
-  const bool nearest_neighbor = true;
-  const gfx::ColorSpace color_space = gfx::ColorSpace(
-      gfx::ColorSpace::PrimaryID::BT470M, gfx::ColorSpace::TransferID::GAMMA28,
-      gfx::ColorSpace::MatrixID::BT2020_NCL, gfx::ColorSpace::RangeID::LIMITED);
-#if defined(OS_ANDROID)
-  const bool is_backed_by_surface_texture = true;
-  const bool wants_promotion_hint = true;
-#endif
-
-  gpu::Mailbox mailbox;
-  mailbox.SetName(mailbox_name);
-  viz::TextureMailbox input(mailbox, sync_token, texture_target, size_in_pixels,
-                            is_overlay_candidate, secure_output_only);
-  input.set_nearest_neighbor(nearest_neighbor);
-  input.set_color_space(color_space);
-#if defined(OS_ANDROID)
-  input.set_is_backed_by_surface_texture(is_backed_by_surface_texture);
-  input.set_wants_promotion_hint(wants_promotion_hint);
-#endif
-
-  mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
-  viz::TextureMailbox output;
-  proxy->EchoTextureMailbox(input, &output);
-
-  EXPECT_EQ(mailbox, output.mailbox());
-  EXPECT_EQ(sync_token, output.sync_token());
-  EXPECT_EQ(texture_target, output.target());
-  EXPECT_EQ(size_in_pixels, output.size_in_pixels());
-  EXPECT_EQ(is_overlay_candidate, output.is_overlay_candidate());
-  EXPECT_EQ(secure_output_only, output.secure_output_only());
-  EXPECT_EQ(nearest_neighbor, output.nearest_neighbor());
-  EXPECT_EQ(color_space, output.color_space());
-#if defined(OS_ANDROID)
-  EXPECT_EQ(is_backed_by_surface_texture,
-            output.is_backed_by_surface_texture());
-  EXPECT_EQ(wants_promotion_hint, output.wants_promotion_hint());
-#endif
-}
-
-}  // namespace cc
diff --git a/cc/ipc/texture_mailbox.typemap b/cc/ipc/texture_mailbox.typemap
deleted file mode 100644
index be37c00b..0000000
--- a/cc/ipc/texture_mailbox.typemap
+++ /dev/null
@@ -1,11 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//cc/ipc/texture_mailbox.mojom"
-public_headers = [ "//components/viz/common/quads/texture_mailbox.h" ]
-traits_headers = [ "//cc/ipc/texture_mailbox_struct_traits.h" ]
-deps = [
-  "//components/viz/common",
-]
-type_mappings = [ "cc.mojom.TextureMailbox=viz::TextureMailbox" ]
diff --git a/cc/ipc/traits_test_service.mojom b/cc/ipc/traits_test_service.mojom
deleted file mode 100644
index a04dfe6..0000000
--- a/cc/ipc/traits_test_service.mojom
+++ /dev/null
@@ -1,19 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-module cc.mojom;
-
-import "cc/ipc/copy_output_result.mojom";
-import "cc/ipc/texture_mailbox.mojom";
-
-// All functions on this interface echo their arguments to test StructTraits
-// serialization and deserialization.
-interface TraitsTestService {
-  [Sync]
-  EchoCopyOutputResult(CopyOutputResult c) => (CopyOutputResult pass);
-
-  [Sync]
-  EchoTextureMailbox(TextureMailbox t) =>
-      (TextureMailbox pass);
-};
diff --git a/cc/ipc/typemaps.gni b/cc/ipc/typemaps.gni
deleted file mode 100644
index d08a133..0000000
--- a/cc/ipc/typemaps.gni
+++ /dev/null
@@ -1,8 +0,0 @@
-# Copyright 2016 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-typemaps = [
-  "//cc/ipc/copy_output_result.typemap",
-  "//cc/ipc/texture_mailbox.typemap",
-]
diff --git a/cc/layers/layer_impl.cc b/cc/layers/layer_impl.cc
index 07094470c..769edce 100644
--- a/cc/layers/layer_impl.cc
+++ b/cc/layers/layer_impl.cc
@@ -461,7 +461,7 @@
   SetNeedsPushProperties();
 }
 
-void LayerImpl::ValidateQuadResourcesInternal(DrawQuad* quad) const {
+void LayerImpl::ValidateQuadResourcesInternal(viz::DrawQuad* quad) const {
 #if DCHECK_IS_ON()
   const ResourceProvider* resource_provider =
       layer_tree_impl_->resource_provider();
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h
index 860bbdb..b9f7ed05 100644
--- a/cc/layers/layer_impl.h
+++ b/cc/layers/layer_impl.h
@@ -144,7 +144,7 @@
   virtual void DidDraw(ResourceProvider* resource_provider);
 
   // Verify that the resource ids in the quad are valid.
-  void ValidateQuadResources(DrawQuad* quad) const {
+  void ValidateQuadResources(viz::DrawQuad* quad) const {
 #if DCHECK_IS_ON()
     ValidateQuadResourcesInternal(quad);
 #endif
@@ -459,7 +459,7 @@
   gfx::Rect GetScaledEnclosingRectInTargetSpace(float scale) const;
 
  private:
-  void ValidateQuadResourcesInternal(DrawQuad* quad) const;
+  void ValidateQuadResourcesInternal(viz::DrawQuad* quad) const;
 
   virtual const char* LayerTypeAsString() const;
 
diff --git a/cc/layers/painted_scrollbar_layer_impl_unittest.cc b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
index f033bf96..32d73f8 100644
--- a/cc/layers/painted_scrollbar_layer_impl_unittest.cc
+++ b/cc/layers/painted_scrollbar_layer_impl_unittest.cc
@@ -6,10 +6,10 @@
 
 #include <stddef.h>
 
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/ui_resource_bitmap.h"
 #include "cc/test/layer_test_common.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace cc {
@@ -77,11 +77,11 @@
     // Note: this is also testing that the thumb and track are both
     // scaled by the internal contents scale.  It's not occlusion-related
     // but is easy to verify here.
-    const DrawQuad* thumb_draw_quad = impl.quad_list().ElementAt(0);
-    const DrawQuad* track_draw_quad = impl.quad_list().ElementAt(1);
+    const viz::DrawQuad* thumb_draw_quad = impl.quad_list().ElementAt(0);
+    const viz::DrawQuad* track_draw_quad = impl.quad_list().ElementAt(1);
 
-    EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, thumb_draw_quad->material);
-    EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, track_draw_quad->material);
+    EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, thumb_draw_quad->material);
+    EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, track_draw_quad->material);
 
     const TextureDrawQuad* thumb_quad =
         TextureDrawQuad::MaterialCast(thumb_draw_quad);
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index f8d81187..aeed423 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -18,7 +18,6 @@
 #include "cc/base/math_util.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/picture_layer.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
@@ -37,6 +36,7 @@
 #include "cc/tiles/tiling_set_raster_queue_all.h"
 #include "cc/tiles/tiling_set_raster_queue_required.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/resources/buffer_to_texture_target_map.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -1525,7 +1525,7 @@
   active_layer()->DidDraw(nullptr);
 
   ASSERT_EQ(1u, render_pass->quad_list.size());
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT,
             render_pass->quad_list.front()->material);
   EXPECT_EQ(render_pass->quad_list.front()->rect, layer_rect);
   EXPECT_FALSE(render_pass->quad_list.front()->needs_blending);
@@ -1563,9 +1563,9 @@
   gfx::Rect quad_visible = gfx::IntersectRects(scaled_visible, scaled_recorded);
 
   ASSERT_EQ(1U, render_pass->quad_list.size());
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT,
             render_pass->quad_list.front()->material);
-  const DrawQuad* quad = render_pass->quad_list.front();
+  const viz::DrawQuad* quad = render_pass->quad_list.front();
   EXPECT_EQ(quad_visible, quad->rect);
   EXPECT_TRUE(quad->shared_quad_state->are_contents_opaque);
   EXPECT_EQ(quad_visible, quad->visible_rect);
@@ -3652,9 +3652,9 @@
   // Even when OOM, quads should be produced, and should be different material
   // from quads with resource.
   EXPECT_LT(max_tiles, render_pass->quad_list.size());
-  EXPECT_EQ(DrawQuad::Material::TILED_CONTENT,
+  EXPECT_EQ(viz::DrawQuad::Material::TILED_CONTENT,
             render_pass->quad_list.front()->material);
-  EXPECT_EQ(DrawQuad::Material::SOLID_COLOR,
+  EXPECT_EQ(viz::DrawQuad::Material::SOLID_COLOR,
             render_pass->quad_list.back()->material);
 }
 
@@ -4371,9 +4371,9 @@
   if (partial_opaque)
     EXPECT_EQ(4u, render_pass->quad_list.size());
 
-  DrawQuad::Material expected = test_for_solid
-                                    ? DrawQuad::Material::SOLID_COLOR
-                                    : DrawQuad::Material::TILED_CONTENT;
+  viz::DrawQuad::Material expected =
+      test_for_solid ? viz::DrawQuad::Material::SOLID_COLOR
+                     : viz::DrawQuad::Material::TILED_CONTENT;
   EXPECT_EQ(expected, render_pass->quad_list.front()->material);
 }
 
@@ -5000,7 +5000,8 @@
   active_layer->DidDraw(nullptr);
 
   ASSERT_FALSE(render_pass->quad_list.empty());
-  EXPECT_EQ(DrawQuad::TILED_CONTENT, render_pass->quad_list.front()->material);
+  EXPECT_EQ(viz::DrawQuad::TILED_CONTENT,
+            render_pass->quad_list.front()->material);
 
   // Tiles are ready at correct scale, so should not set had_incomplete_tile.
   EXPECT_EQ(0, data.num_incomplete_tiles);
diff --git a/cc/layers/render_surface_impl.cc b/cc/layers/render_surface_impl.cc
index 192366d..4cb8098 100644
--- a/cc/layers/render_surface_impl.cc
+++ b/cc/layers/render_surface_impl.cc
@@ -505,7 +505,7 @@
         -content_rect().OffsetFromOrigin());
 
     switch (temp_quad->material) {
-      case DrawQuad::TILED_CONTENT: {
+      case viz::DrawQuad::TILED_CONTENT: {
         DCHECK_EQ(1U, temp_quad->resources.count);
         gfx::Size mask_texture_size =
             static_cast<ContentDrawQuadBase*>(temp_quad)->texture_size;
@@ -532,7 +532,7 @@
                      FiltersOrigin(),
                      quad_rect_in_non_normalized_texture_space);
       } break;
-      case DrawQuad::SOLID_COLOR: {
+      case viz::DrawQuad::SOLID_COLOR: {
         if (!static_cast<SolidColorDrawQuad*>(temp_quad)->color)
           continue;
         SkAlpha solid = SK_AlphaOPAQUE;
@@ -548,7 +548,7 @@
                      FiltersOrigin(),
                      quad_rect_in_non_normalized_texture_space);
       } break;
-      case DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         NOTIMPLEMENTED();
         break;
       default:
diff --git a/cc/layers/scrollbar_layer_unittest.cc b/cc/layers/scrollbar_layer_unittest.cc
index 14d0363..ab56cd8 100644
--- a/cc/layers/scrollbar_layer_unittest.cc
+++ b/cc/layers/scrollbar_layer_unittest.cc
@@ -553,7 +553,7 @@
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
     EXPECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
   }
 
@@ -568,7 +568,7 @@
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
     EXPECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
   }
 
@@ -583,7 +583,7 @@
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
     EXPECT_EQ(gfx::Rect(1, 0, 98, 3), quads.front()->rect);
   }
 }
@@ -640,7 +640,7 @@
 
     const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, quads.front()->material);
     EXPECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
   }
 }
diff --git a/cc/layers/texture_layer_impl_unittest.cc b/cc/layers/texture_layer_impl_unittest.cc
index 0dc3a8c..c81a410c 100644
--- a/cc/layers/texture_layer_impl_unittest.cc
+++ b/cc/layers/texture_layer_impl_unittest.cc
@@ -7,11 +7,11 @@
 #include <stddef.h>
 
 #include "cc/output/layer_tree_frame_sink.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/test/fake_layer_tree_frame_sink.h"
 #include "cc/test/layer_test_common.h"
 #include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -140,7 +140,7 @@
     impl.AppendQuadsWithOcclusion(texture_layer_impl, occluded);
 
     EXPECT_EQ(1u, impl.quad_list().size());
-    ASSERT_EQ(DrawQuad::Material::TEXTURE_CONTENT,
+    ASSERT_EQ(viz::DrawQuad::Material::TEXTURE_CONTENT,
               impl.quad_list().front()->material);
     const TextureDrawQuad* quad =
         TextureDrawQuad::MaterialCast(impl.quad_list().front());
diff --git a/cc/layers/ui_resource_layer_impl_unittest.cc b/cc/layers/ui_resource_layer_impl_unittest.cc
index 9b302eef..bd2df3a 100644
--- a/cc/layers/ui_resource_layer_impl_unittest.cc
+++ b/cc/layers/ui_resource_layer_impl_unittest.cc
@@ -6,7 +6,6 @@
 
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/ui_resource_layer_impl.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/resources/ui_resource_bitmap.h"
 #include "cc/resources/ui_resource_client.h"
 #include "cc/test/fake_impl_task_runner_provider.h"
@@ -16,6 +15,7 @@
 #include "cc/test/layer_test_common.h"
 #include "cc/test/test_task_graph_runner.h"
 #include "cc/trees/single_thread_proxy.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/transform.h"
diff --git a/cc/layers/video_layer_impl_unittest.cc b/cc/layers/video_layer_impl_unittest.cc
index 7f0adc3d..6f50578 100644
--- a/cc/layers/video_layer_impl_unittest.cc
+++ b/cc/layers/video_layer_impl_unittest.cc
@@ -8,7 +8,6 @@
 
 #include "cc/layers/video_frame_provider_client_impl.h"
 #include "cc/output/output_surface.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/stream_video_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
@@ -16,6 +15,7 @@
 #include "cc/test/layer_test_common.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "components/viz/common/gpu/context_provider.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "media/base/video_frame.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -320,8 +320,8 @@
   impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
 
   EXPECT_EQ(1u, impl.quad_list().size());
-  const DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+  const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
+  ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
 
   const YUVVideoDrawQuad* yuv_draw_quad =
       static_cast<const YUVVideoDrawQuad*>(draw_quad);
@@ -366,8 +366,8 @@
   impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
 
   EXPECT_EQ(1u, impl.quad_list().size());
-  const DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
+  const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
+  ASSERT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, draw_quad->material);
 
   const YUVVideoDrawQuad* yuv_draw_quad =
       static_cast<const YUVVideoDrawQuad*>(draw_quad);
@@ -410,8 +410,8 @@
   impl.AppendQuadsWithOcclusion(video_layer_impl, occluded);
 
   EXPECT_EQ(1u, impl.quad_list().size());
-  const DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
-  ASSERT_EQ(DrawQuad::TEXTURE_CONTENT, draw_quad->material);
+  const viz::DrawQuad* draw_quad = impl.quad_list().ElementAt(0);
+  ASSERT_EQ(viz::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
 
   const TextureDrawQuad* texture_draw_quad =
       TextureDrawQuad::MaterialCast(draw_quad);
diff --git a/cc/output/bsp_tree_perftest.cc b/cc/output/bsp_tree_perftest.cc
index d297eb0..84f437d 100644
--- a/cc/output/bsp_tree_perftest.cc
+++ b/cc/output/bsp_tree_perftest.cc
@@ -18,7 +18,6 @@
 #include "cc/layers/layer.h"
 #include "cc/output/bsp_tree.h"
 #include "cc/quads/draw_polygon.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_layer_tree_host_client.h"
 #include "cc/test/layer_tree_json_parser.h"
diff --git a/cc/output/bsp_walk_action.cc b/cc/output/bsp_walk_action.cc
index 5acbc50..625ff60 100644
--- a/cc/output/bsp_walk_action.cc
+++ b/cc/output/bsp_walk_action.cc
@@ -9,7 +9,7 @@
 
 #include "cc/output/direct_renderer.h"
 #include "cc/quads/draw_polygon.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 namespace cc {
 
diff --git a/cc/output/ca_layer_overlay.cc b/cc/output/ca_layer_overlay.cc
index d9943f8f..0f25fdeb 100644
--- a/cc/output/ca_layer_overlay.cc
+++ b/cc/output/ca_layer_overlay.cc
@@ -177,7 +177,7 @@
   CALayerResult FromDrawQuad(
       ResourceProvider* resource_provider,
       const gfx::RectF& display_rect,
-      const DrawQuad* quad,
+      const viz::DrawQuad* quad,
       const base::flat_map<RenderPassId, FilterOperations*>&
           render_pass_filters,
       const base::flat_map<RenderPassId, FilterOperations*>&
@@ -225,34 +225,34 @@
 
     ca_layer_overlay->bounds_rect = gfx::RectF(quad->rect);
 
-    *render_pass_draw_quad = quad->material == DrawQuad::RENDER_PASS;
+    *render_pass_draw_quad = quad->material == viz::DrawQuad::RENDER_PASS;
     switch (quad->material) {
-      case DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         return FromTextureQuad(resource_provider,
                                TextureDrawQuad::MaterialCast(quad),
                                ca_layer_overlay);
-      case DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad),
                             ca_layer_overlay);
-      case DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         return FromSolidColorDrawQuad(SolidColorDrawQuad::MaterialCast(quad),
                                       ca_layer_overlay, skip);
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         return FromStreamVideoQuad(resource_provider,
                                    StreamVideoDrawQuad::MaterialCast(quad),
                                    ca_layer_overlay);
-      case DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         return CA_LAYER_FAILED_DEBUG_BORDER;
-      case DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         return CA_LAYER_FAILED_PICTURE_CONTENT;
-      case DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         return FromRenderPassQuad(
             resource_provider, RenderPassDrawQuad::MaterialCast(quad),
             render_pass_filters, render_pass_background_filters,
             ca_layer_overlay);
-      case DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         return CA_LAYER_FAILED_SURFACE_CONTENT;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         return CA_LAYER_FAILED_YUV_VIDEO_CONTENT;
       default:
         break;
@@ -289,7 +289,7 @@
   CALayerOverlayProcessor processor;
   for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
        ++it) {
-    const DrawQuad* quad = *it;
+    const viz::DrawQuad* quad = *it;
     CALayerOverlay ca_layer;
     bool skip = false;
     bool render_pass_draw_quad = false;
diff --git a/cc/output/dc_layer_overlay.cc b/cc/output/dc_layer_overlay.cc
index e1602f19..8741341 100644
--- a/cc/output/dc_layer_overlay.cc
+++ b/cc/output/dc_layer_overlay.cc
@@ -35,7 +35,7 @@
 }
 
 // This returns the smallest rectangle in target space that contains the quad.
-gfx::RectF ClippedQuadRectangle(const DrawQuad* quad) {
+gfx::RectF ClippedQuadRectangle(const viz::DrawQuad* quad) {
   gfx::RectF quad_rect = MathUtil::MapClippedRect(
       quad->shared_quad_state->quad_to_target_transform,
       gfx::RectF(quad->rect));
@@ -55,9 +55,9 @@
     float opacity = overlap_iter->shared_quad_state->opacity;
     if (opacity < std::numeric_limits<float>::epsilon())
       continue;
-    const DrawQuad* quad = *overlap_iter;
+    const viz::DrawQuad* quad = *overlap_iter;
     gfx::RectF overlap_rect = ClippedQuadRectangle(quad);
-    if (quad->material == DrawQuad::SOLID_COLOR) {
+    if (quad->material == viz::DrawQuad::SOLID_COLOR) {
       SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
       float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
       if (quad->ShouldDrawWithBlending() &&
@@ -100,7 +100,7 @@
 
   DCLayerResult result;
   switch (quad->material) {
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case viz::DrawQuad::YUV_VIDEO_CONTENT:
       result =
           FromYUVQuad(resource_provider, YUVVideoDrawQuad::MaterialCast(*quad),
                       ca_layer_overlay);
@@ -158,7 +158,7 @@
     RenderPass* render_pass,
     gfx::Rect* damage_rect,
     QuadList::Iterator it) {
-  DCHECK_EQ(DrawQuad::RENDER_PASS, it->material);
+  DCHECK_EQ(viz::DrawQuad::RENDER_PASS, it->material);
   const RenderPassDrawQuad* rpdq = RenderPassDrawQuad::MaterialCast(*it);
 
   ++it;
@@ -235,7 +235,7 @@
     // next_it may be modified inside the loop if methods modify the quad list
     // and invalidate iterators to it.
 
-    if (it->material == DrawQuad::RENDER_PASS) {
+    if (it->material == viz::DrawQuad::RENDER_PASS) {
       next_it = ProcessRenderPassDrawQuad(render_pass, damage_rect, it);
       continue;
     }
diff --git a/cc/output/dc_layer_overlay.h b/cc/output/dc_layer_overlay.h
index 4f3b68e..4599f64ae 100644
--- a/cc/output/dc_layer_overlay.h
+++ b/cc/output/dc_layer_overlay.h
@@ -47,7 +47,7 @@
 
   // Resource ids that correspond to the DXGI textures to set as the contents
   // of the DCLayer.
-  DrawQuad::Resources resources;
+  viz::DrawQuad::Resources resources;
   // The contents rect property for the DCLayer.
   gfx::RectF contents_rect;
   // The bounds for the DCLayer in pixels.
diff --git a/cc/output/direct_renderer.cc b/cc/output/direct_renderer.cc
index 54363ed..ea5fae1 100644
--- a/cc/output/direct_renderer.cc
+++ b/cc/output/direct_renderer.cc
@@ -17,10 +17,10 @@
 #include "cc/output/bsp_tree.h"
 #include "cc/output/bsp_walk_action.h"
 #include "cc/output/output_surface.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/resources/scoped_resource.h"
 #include "components/viz/common/display/renderer_settings.h"
 #include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/geometry/quad_f.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
@@ -404,7 +404,7 @@
   }
 }
 
-bool DirectRenderer::ShouldSkipQuad(const DrawQuad& quad,
+bool DirectRenderer::ShouldSkipQuad(const viz::DrawQuad& quad,
                                     const gfx::Rect& render_pass_scissor) {
   if (render_pass_scissor.IsEmpty())
     return true;
@@ -419,7 +419,7 @@
 }
 
 void DirectRenderer::SetScissorStateForQuad(
-    const DrawQuad& quad,
+    const viz::DrawQuad& quad,
     const gfx::Rect& render_pass_scissor,
     bool use_render_pass_scissor) {
   if (use_render_pass_scissor) {
@@ -573,7 +573,7 @@
   int last_sorting_context_id = 0;
   for (auto it = quad_list.BackToFrontBegin(); it != quad_list.BackToFrontEnd();
        ++it) {
-    const DrawQuad& quad = **it;
+    const viz::DrawQuad& quad = **it;
 
     if (render_pass_is_clipped &&
         ShouldSkipQuad(quad, render_pass_scissor_in_draw_space)) {
diff --git a/cc/output/direct_renderer.h b/cc/output/direct_renderer.h
index a6c2b079..c9dd275 100644
--- a/cc/output/direct_renderer.h
+++ b/cc/output/direct_renderer.h
@@ -123,10 +123,10 @@
 
   gfx::Rect DeviceViewportRectInDrawSpace() const;
   gfx::Rect OutputSurfaceRectInDrawSpace() const;
-  void SetScissorStateForQuad(const DrawQuad& quad,
+  void SetScissorStateForQuad(const viz::DrawQuad& quad,
                               const gfx::Rect& render_pass_scissor,
                               bool use_render_pass_scissor);
-  bool ShouldSkipQuad(const DrawQuad& quad,
+  bool ShouldSkipQuad(const viz::DrawQuad& quad,
                       const gfx::Rect& render_pass_scissor);
   void SetScissorTestRectInDrawSpace(const gfx::Rect& draw_space_rect);
 
@@ -159,7 +159,7 @@
   // |clip_region| is a (possibly null) pointer to a quad in the same
   // space as the quad. When non-null only the area of the quad that overlaps
   // with clip_region will be drawn.
-  virtual void DoDrawQuad(const DrawQuad* quad,
+  virtual void DoDrawQuad(const viz::DrawQuad* quad,
                           const gfx::QuadF* clip_region) = 0;
   virtual void BeginDrawingFrame() = 0;
   virtual void FinishDrawingFrame() = 0;
diff --git a/cc/output/overlay_candidate.cc b/cc/output/overlay_candidate.cc
index b4583c4..c51c7ccd 100644
--- a/cc/output/overlay_candidate.cc
+++ b/cc/output/overlay_candidate.cc
@@ -194,7 +194,7 @@
 
 // static
 bool OverlayCandidate::FromDrawQuad(DisplayResourceProvider* resource_provider,
-                                    const DrawQuad* quad,
+                                    const viz::DrawQuad* quad,
                                     OverlayCandidate* candidate) {
   // We don't support an opacity value different than one for an overlay plane.
   if (quad->shared_quad_state->opacity != 1.f)
@@ -205,13 +205,13 @@
     return false;
 
   switch (quad->material) {
-    case DrawQuad::TEXTURE_CONTENT:
+    case viz::DrawQuad::TEXTURE_CONTENT:
       return FromTextureQuad(resource_provider,
                              TextureDrawQuad::MaterialCast(quad), candidate);
-    case DrawQuad::TILED_CONTENT:
+    case viz::DrawQuad::TILED_CONTENT:
       return FromTileQuad(resource_provider, TileDrawQuad::MaterialCast(quad),
                           candidate);
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case viz::DrawQuad::STREAM_VIDEO_CONTENT:
       return FromStreamVideoQuad(resource_provider,
                                  StreamVideoDrawQuad::MaterialCast(quad),
                                  candidate);
@@ -223,11 +223,11 @@
 }
 
 // static
-bool OverlayCandidate::IsInvisibleQuad(const DrawQuad* quad) {
+bool OverlayCandidate::IsInvisibleQuad(const viz::DrawQuad* quad) {
   float opacity = quad->shared_quad_state->opacity;
   if (opacity < std::numeric_limits<float>::epsilon())
     return true;
-  if (quad->material == DrawQuad::SOLID_COLOR) {
+  if (quad->material == viz::DrawQuad::SOLID_COLOR) {
     SkColor color = SolidColorDrawQuad::MaterialCast(quad)->color;
     float alpha = (SkColorGetA(color) * (1.0f / 255.0f)) * opacity;
     return quad->ShouldDrawWithBlending() &&
@@ -256,7 +256,7 @@
 // static
 bool OverlayCandidate::FromDrawQuadResource(
     DisplayResourceProvider* resource_provider,
-    const DrawQuad* quad,
+    const viz::DrawQuad* quad,
     viz::ResourceId resource_id,
     bool y_flipped,
     OverlayCandidate* candidate) {
diff --git a/cc/output/overlay_candidate.h b/cc/output/overlay_candidate.h
index fdd0f7e60..3dfd79d 100644
--- a/cc/output/overlay_candidate.h
+++ b/cc/output/overlay_candidate.h
@@ -35,11 +35,11 @@
   // Returns true and fills in |candidate| if |draw_quad| is of a known quad
   // type and contains an overlayable resource.
   static bool FromDrawQuad(DisplayResourceProvider* resource_provider,
-                           const DrawQuad* quad,
+                           const viz::DrawQuad* quad,
                            OverlayCandidate* candidate);
   // Returns true if |quad| will not block quads underneath from becoming
   // an overlay.
-  static bool IsInvisibleQuad(const DrawQuad* quad);
+  static bool IsInvisibleQuad(const viz::DrawQuad* quad);
 
   // Returns true if any any of the quads in the list given by |quad_list_begin|
   // and |quad_list_end| are visible and on top of |candidate|.
@@ -99,7 +99,7 @@
 
  private:
   static bool FromDrawQuadResource(DisplayResourceProvider* resource_provider,
-                                   const DrawQuad* quad,
+                                   const viz::DrawQuad* quad,
                                    viz::ResourceId resource_id,
                                    bool y_flipped,
                                    OverlayCandidate* candidate);
diff --git a/cc/output/overlay_processor.cc b/cc/output/overlay_processor.cc
index 5a1ee11f..f293a4c 100644
--- a/cc/output/overlay_processor.cc
+++ b/cc/output/overlay_processor.cc
@@ -8,7 +8,6 @@
 #include "cc/output/output_surface.h"
 #include "cc/output/overlay_strategy_single_on_top.h"
 #include "cc/output/overlay_strategy_underlay.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/resources/display_resource_provider.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/transform.h"
diff --git a/cc/output/overlay_strategy_fullscreen.cc b/cc/output/overlay_strategy_fullscreen.cc
index eedd2d3c..424c776 100644
--- a/cc/output/overlay_strategy_fullscreen.cc
+++ b/cc/output/overlay_strategy_fullscreen.cc
@@ -6,8 +6,8 @@
 
 #include "cc/base/math_util.h"
 #include "cc/output/overlay_candidate_validator.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/size_conversions.h"
 
@@ -38,7 +38,7 @@
   if (front == quad_list->end())
     return false;
 
-  const DrawQuad* quad = *front;
+  const viz::DrawQuad* quad = *front;
   if (quad->ShouldDrawWithBlending())
     return false;
 
diff --git a/cc/output/overlay_strategy_single_on_top.cc b/cc/output/overlay_strategy_single_on_top.cc
index 138a889e..0f9c59a 100644
--- a/cc/output/overlay_strategy_single_on_top.cc
+++ b/cc/output/overlay_strategy_single_on_top.cc
@@ -6,7 +6,6 @@
 
 #include "cc/base/math_util.h"
 #include "cc/output/overlay_candidate_validator.h"
-#include "cc/quads/draw_quad.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
diff --git a/cc/output/overlay_strategy_underlay.cc b/cc/output/overlay_strategy_underlay.cc
index 70d2daf..9b7e4474 100644
--- a/cc/output/overlay_strategy_underlay.cc
+++ b/cc/output/overlay_strategy_underlay.cc
@@ -5,8 +5,8 @@
 #include "cc/output/overlay_strategy_underlay.h"
 
 #include "cc/output/overlay_candidate_validator.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 namespace cc {
 
diff --git a/cc/output/overlay_strategy_underlay_cast.cc b/cc/output/overlay_strategy_underlay_cast.cc
index bbe3fac8..15d3060 100644
--- a/cc/output/overlay_strategy_underlay_cast.cc
+++ b/cc/output/overlay_strategy_underlay_cast.cc
@@ -5,8 +5,8 @@
 #include "cc/output/overlay_strategy_underlay_cast.h"
 
 #include "base/containers/adapters.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/solid_color_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 
 namespace cc {
@@ -41,7 +41,7 @@
       found_underlay = is_underlay;
     }
 
-    if (!found_underlay && quad->material == DrawQuad::SOLID_COLOR) {
+    if (!found_underlay && quad->material == viz::DrawQuad::SOLID_COLOR) {
       const SolidColorDrawQuad* solid = SolidColorDrawQuad::MaterialCast(quad);
       if (solid->color == SK_ColorBLACK)
         continue;
diff --git a/cc/output/overlay_unittest.cc b/cc/output/overlay_unittest.cc
index 9718cc70..b8e7307 100644
--- a/cc/output/overlay_unittest.cc
+++ b/cc/output/overlay_unittest.cc
@@ -694,7 +694,7 @@
   ASSERT_EQ(1U, candidate_list.size());
 
   // Check that the fullscreen quad is gone.
-  for (const DrawQuad* quad : main_pass->quad_list) {
+  for (const viz::DrawQuad* quad : main_pass->quad_list) {
     EXPECT_NE(main_pass->output_rect, quad->rect);
   }
 }
@@ -732,7 +732,7 @@
   for (QuadList::ConstBackToFrontIterator it = quad_list.BackToFrontBegin();
        it != quad_list.BackToFrontEnd();
        ++it) {
-    EXPECT_NE(DrawQuad::TEXTURE_CONTENT, it->material);
+    EXPECT_NE(viz::DrawQuad::TEXTURE_CONTENT, it->material);
   }
 
   // Check that the right resource id got extracted.
@@ -1409,7 +1409,7 @@
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   EXPECT_EQ(2U, main_pass->quad_list.size());
   // The overlay quad should have changed to a SOLID_COLOR quad.
-  EXPECT_EQ(main_pass->quad_list.back()->material, DrawQuad::SOLID_COLOR);
+  EXPECT_EQ(main_pass->quad_list.back()->material, viz::DrawQuad::SOLID_COLOR);
   SolidColorDrawQuad* quad =
       static_cast<SolidColorDrawQuad*>(main_pass->quad_list.back());
   EXPECT_EQ(quad->rect, quad->visible_rect);
@@ -1439,7 +1439,7 @@
   ASSERT_EQ(1U, candidate_list.size());
   EXPECT_EQ(-1, candidate_list[0].plane_z_order);
   // The overlay quad should have changed to a SOLID_COLOR quad.
-  EXPECT_EQ(main_pass->quad_list.front()->material, DrawQuad::SOLID_COLOR);
+  EXPECT_EQ(main_pass->quad_list.front()->material, viz::DrawQuad::SOLID_COLOR);
   SolidColorDrawQuad* quad =
       static_cast<SolidColorDrawQuad*>(main_pass->quad_list.front());
   EXPECT_EQ(quad->rect, quad->visible_rect);
@@ -2276,7 +2276,7 @@
         expect_overlays_(false) {}
 
   MOCK_METHOD2(DoDrawQuad,
-               void(const DrawQuad* quad, const gfx::QuadF* draw_region));
+               void(const viz::DrawQuad* quad, const gfx::QuadF* draw_region));
 
   void SetCurrentFrame(const DrawingFrame& frame) {
     SetCurrentFrameForTesting(frame);
diff --git a/cc/output/renderer_pixeltest.cc b/cc/output/renderer_pixeltest.cc
index dcc66777..92398bd 100644
--- a/cc/output/renderer_pixeltest.cc
+++ b/cc/output/renderer_pixeltest.cc
@@ -11,7 +11,6 @@
 #include "cc/base/math_util.h"
 #include "cc/paint/paint_flags.h"
 #include "cc/paint/skia_paint_canvas.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/picture_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/video_resource_updater.h"
diff --git a/cc/output/software_renderer.cc b/cc/output/software_renderer.cc
index 2fc72ea..7e66524 100644
--- a/cc/output/software_renderer.cc
+++ b/cc/output/software_renderer.cc
@@ -206,7 +206,7 @@
   return false;
 }
 
-void SoftwareRenderer::DoDrawQuad(const DrawQuad* quad,
+void SoftwareRenderer::DoDrawQuad(const viz::DrawQuad* quad,
                                   const gfx::QuadF* draw_region) {
   if (!current_canvas_)
     return;
@@ -271,32 +271,32 @@
   }
 
   switch (quad->material) {
-    case DrawQuad::DEBUG_BORDER:
+    case viz::DrawQuad::DEBUG_BORDER:
       DrawDebugBorderQuad(DebugBorderDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case viz::DrawQuad::PICTURE_CONTENT:
       DrawPictureQuad(PictureDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::RENDER_PASS:
+    case viz::DrawQuad::RENDER_PASS:
       DrawRenderPassQuad(RenderPassDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::SOLID_COLOR:
+    case viz::DrawQuad::SOLID_COLOR:
       DrawSolidColorQuad(SolidColorDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case viz::DrawQuad::TEXTURE_CONTENT:
       DrawTextureQuad(TextureDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::TILED_CONTENT:
+    case viz::DrawQuad::TILED_CONTENT:
       DrawTileQuad(TileDrawQuad::MaterialCast(quad));
       break;
-    case DrawQuad::SURFACE_CONTENT:
+    case viz::DrawQuad::SURFACE_CONTENT:
       // Surface content should be fully resolved to other quad types before
       // reaching a direct renderer.
       NOTREACHED();
       break;
-    case DrawQuad::INVALID:
-    case DrawQuad::YUV_VIDEO_CONTENT:
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case viz::DrawQuad::INVALID:
+    case viz::DrawQuad::YUV_VIDEO_CONTENT:
+    case viz::DrawQuad::STREAM_VIDEO_CONTENT:
       DrawUnsupportedQuad(quad);
       NOTREACHED();
       break;
@@ -553,7 +553,7 @@
   current_canvas_->drawRect(dest_visible_rect, current_paint_);
 }
 
-void SoftwareRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
+void SoftwareRenderer::DrawUnsupportedQuad(const viz::DrawQuad* quad) {
 #ifdef NDEBUG
   current_paint_.setColor(SK_ColorWHITE);
 #else
diff --git a/cc/output/software_renderer.h b/cc/output/software_renderer.h
index 54fbbf32..c40f013 100644
--- a/cc/output/software_renderer.h
+++ b/cc/output/software_renderer.h
@@ -43,7 +43,8 @@
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
-  void DoDrawQuad(const DrawQuad* quad, const gfx::QuadF* draw_region) override;
+  void DoDrawQuad(const viz::DrawQuad* quad,
+                  const gfx::QuadF* draw_region) override;
   void BeginDrawingFrame() override;
   void FinishDrawingFrame() override;
   bool FlippedFramebuffer() const override;
@@ -66,7 +67,7 @@
   void DrawSolidColorQuad(const SolidColorDrawQuad* quad);
   void DrawTextureQuad(const TextureDrawQuad* quad);
   void DrawTileQuad(const TileDrawQuad* quad);
-  void DrawUnsupportedQuad(const DrawQuad* quad);
+  void DrawUnsupportedQuad(const viz::DrawQuad* quad);
   bool ShouldApplyBackgroundFilters(
       const RenderPassDrawQuad* quad,
       const FilterOperations* background_filters) const;
diff --git a/cc/output/vulkan_renderer.cc b/cc/output/vulkan_renderer.cc
index 019abe2d..dc917ed4 100644
--- a/cc/output/vulkan_renderer.cc
+++ b/cc/output/vulkan_renderer.cc
@@ -48,7 +48,7 @@
 }
 
 void VulkanRenderer::DoDrawQuad(DrawingFrame* frame,
-                                const DrawQuad* quad,
+                                const viz::DrawQuad* quad,
                                 const gfx::QuadF* clip_region) {
   NOTIMPLEMENTED();
 }
diff --git a/cc/output/vulkan_renderer.h b/cc/output/vulkan_renderer.h
index 584e86d..32b2cd9 100644
--- a/cc/output/vulkan_renderer.h
+++ b/cc/output/vulkan_renderer.h
@@ -38,7 +38,7 @@
                              SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
   void DoDrawQuad(DrawingFrame* frame,
-                  const DrawQuad* quad,
+                  const viz::DrawQuad* quad,
                   const gfx::QuadF* clip_region) override;
   void BeginDrawingFrame(DrawingFrame* frame) override;
   void FinishDrawingFrame(DrawingFrame* frame) override;
diff --git a/cc/paint/paint_image.cc b/cc/paint/paint_image.cc
index 359958df..7dba184 100644
--- a/cc/paint/paint_image.cc
+++ b/cc/paint/paint_image.cc
@@ -99,8 +99,13 @@
 
 SkISize PaintImage::GetSupportedDecodeSize(
     const SkISize& requested_size) const {
-  // TODO(vmpstr): For now, we ignore the requested size and just return the
-  // available image size.
+  // TODO(vmpstr): If this image is using subset_rect, then we don't support
+  // decoding to any scale other than the original. See the comment in Decode()
+  // explaining this in more detail.
+  // TODO(vmpstr): For now, always decode to the original size. This can be
+  // enabled with the following code, and should be done as a follow-up.
+  //  if (paint_image_generator_ && subset_rect_.IsEmpty())
+  //    return paint_image_generator_->GetSupportedDecodeSize(requested_size);
   return SkISize::Make(width(), height());
 }
 
@@ -114,6 +119,65 @@
 bool PaintImage::Decode(void* memory,
                         SkImageInfo* info,
                         sk_sp<SkColorSpace> color_space) const {
+  // We only support decode to supported decode size.
+  DCHECK(info->dimensions() == GetSupportedDecodeSize(info->dimensions()));
+
+  // TODO(vmpstr): If we're using a subset_rect_ then the info specifies the
+  // requested size relative to the subset. However, the generator isn't aware
+  // of this subsetting and would need a size that is relative to the original
+  // image size. We could still implement this case, but we need to convert the
+  // requested size into the space of the original image. For now, fallback to
+  // DecodeFromSkImage().
+  if (paint_image_generator_ && subset_rect_.IsEmpty())
+    return DecodeFromGenerator(memory, info, std::move(color_space));
+  return DecodeFromSkImage(memory, info, std::move(color_space));
+}
+
+bool PaintImage::DecodeFromGenerator(void* memory,
+                                     SkImageInfo* info,
+                                     sk_sp<SkColorSpace> color_space) const {
+  DCHECK(subset_rect_.IsEmpty());
+
+  // First convert the info to have the requested color space, since the decoder
+  // will convert this for us.
+  *info = info->makeColorSpace(std::move(color_space));
+  if (info->colorType() != kN32_SkColorType) {
+    // Since the decoders only support N32 color types, make one of those and
+    // decode into temporary memory. Then read the bitmap which will convert it
+    // to the target color type.
+    SkImageInfo n32info = info->makeColorType(kN32_SkColorType);
+    std::unique_ptr<char[]> n32memory(
+        new char[n32info.minRowBytes() * n32info.height()]);
+
+    bool result = paint_image_generator_->GetPixels(n32info, n32memory.get(),
+                                                    n32info.minRowBytes(),
+                                                    frame_index(), unique_id());
+    if (!result)
+      return false;
+
+    // The following block will use Skia to do the color type conversion from
+    // N32 to the destination color type. Since color space conversion was
+    // already done in GetPixels() above, remove the color space information
+    // first in case Skia tries to use it for something. In practice, n32info
+    // and *info color spaces match, so it should work without removing the
+    // color spaces, but better be safe.
+    SkImageInfo n32info_no_colorspace = n32info.makeColorSpace(nullptr);
+    SkImageInfo info_no_colorspace = info->makeColorSpace(nullptr);
+
+    SkBitmap bitmap;
+    bitmap.installPixels(n32info_no_colorspace, n32memory.get(),
+                         n32info.minRowBytes());
+    return bitmap.readPixels(info_no_colorspace, memory, info->minRowBytes(), 0,
+                             0);
+  }
+
+  return paint_image_generator_->GetPixels(*info, memory, info->minRowBytes(),
+                                           frame_index(), unique_id());
+}
+
+bool PaintImage::DecodeFromSkImage(void* memory,
+                                   SkImageInfo* info,
+                                   sk_sp<SkColorSpace> color_space) const {
   auto image = GetSkImage();
   DCHECK(image);
   if (color_space) {
@@ -126,7 +190,7 @@
   // given color space, since it can produce incorrect results.
   bool result = image->readPixels(*info, memory, info->minRowBytes(), 0, 0,
                                   SkImage::kDisallow_CachingHint);
-  *info = info->makeColorSpace(color_space);
+  *info = info->makeColorSpace(std::move(color_space));
   return result;
 }
 
diff --git a/cc/paint/paint_image.h b/cc/paint/paint_image.h
index e1781c3..1478d6e 100644
--- a/cc/paint/paint_image.h
+++ b/cc/paint/paint_image.h
@@ -147,6 +147,13 @@
   friend class PaintImageBuilder;
   FRIEND_TEST_ALL_PREFIXES(PaintImageTest, Subsetting);
 
+  bool DecodeFromGenerator(void* memory,
+                           SkImageInfo* info,
+                           sk_sp<SkColorSpace> color_space) const;
+  bool DecodeFromSkImage(void* memory,
+                         SkImageInfo* info,
+                         sk_sp<SkColorSpace> color_space) const;
+
   sk_sp<SkImage> sk_image_;
 
   sk_sp<PaintRecord> paint_record_;
diff --git a/cc/quads/content_draw_quad_base.cc b/cc/quads/content_draw_quad_base.cc
index 18e9e766..06249b5 100644
--- a/cc/quads/content_draw_quad_base.cc
+++ b/cc/quads/content_draw_quad_base.cc
@@ -19,7 +19,7 @@
 }
 
 void ContentDrawQuadBase::SetNew(const viz::SharedQuadState* shared_quad_state,
-                                 DrawQuad::Material material,
+                                 viz::DrawQuad::Material material,
                                  const gfx::Rect& rect,
                                  const gfx::Rect& visible_rect,
                                  bool needs_blending,
@@ -27,8 +27,8 @@
                                  const gfx::Size& texture_size,
                                  bool swizzle_contents,
                                  bool nearest_neighbor) {
-  DrawQuad::SetAll(shared_quad_state, material, rect, visible_rect,
-                   needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, material, rect, visible_rect,
+                        needs_blending);
   this->tex_coord_rect = tex_coord_rect;
   this->texture_size = texture_size;
   this->swizzle_contents = swizzle_contents;
@@ -36,7 +36,7 @@
 }
 
 void ContentDrawQuadBase::SetAll(const viz::SharedQuadState* shared_quad_state,
-                                 DrawQuad::Material material,
+                                 viz::DrawQuad::Material material,
                                  const gfx::Rect& rect,
                                  const gfx::Rect& visible_rect,
                                  bool needs_blending,
@@ -44,8 +44,8 @@
                                  const gfx::Size& texture_size,
                                  bool swizzle_contents,
                                  bool nearest_neighbor) {
-  DrawQuad::SetAll(shared_quad_state, material, rect, visible_rect,
-                   needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, material, rect, visible_rect,
+                        needs_blending);
   this->tex_coord_rect = tex_coord_rect;
   this->texture_size = texture_size;
   this->swizzle_contents = swizzle_contents;
diff --git a/cc/quads/content_draw_quad_base.h b/cc/quads/content_draw_quad_base.h
index 08dba856..4f5b037 100644
--- a/cc/quads/content_draw_quad_base.h
+++ b/cc/quads/content_draw_quad_base.h
@@ -8,7 +8,7 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
 
@@ -18,10 +18,10 @@
 
 namespace cc {
 
-class CC_EXPORT ContentDrawQuadBase : public DrawQuad {
+class CC_EXPORT ContentDrawQuadBase : public viz::DrawQuad {
  public:
   void SetNew(const viz::SharedQuadState* shared_quad_state,
-              DrawQuad::Material material,
+              viz::DrawQuad::Material material,
               const gfx::Rect& rect,
               const gfx::Rect& visible_rect,
               bool needs_blending,
@@ -31,7 +31,7 @@
               bool nearest_neighbor);
 
   void SetAll(const viz::SharedQuadState* shared_quad_state,
-              DrawQuad::Material material,
+              viz::DrawQuad::Material material,
               const gfx::Rect& rect,
               const gfx::Rect& visible_rect,
               bool needs_blending,
diff --git a/cc/quads/debug_border_draw_quad.cc b/cc/quads/debug_border_draw_quad.cc
index cabffff..bce77af 100644
--- a/cc/quads/debug_border_draw_quad.cc
+++ b/cc/quads/debug_border_draw_quad.cc
@@ -21,8 +21,8 @@
                                  SkColor color,
                                  int width) {
   bool needs_blending = SkColorGetA(color) < 255;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::DEBUG_BORDER, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::DEBUG_BORDER, rect,
+                        visible_rect, needs_blending);
   this->color = color;
   this->width = width;
 }
@@ -33,15 +33,15 @@
                                  bool needs_blending,
                                  SkColor color,
                                  int width) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::DEBUG_BORDER, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::DEBUG_BORDER, rect,
+                        visible_rect, needs_blending);
   this->color = color;
   this->width = width;
 }
 
 const DebugBorderDrawQuad* DebugBorderDrawQuad::MaterialCast(
-    const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::DEBUG_BORDER);
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::DEBUG_BORDER);
   return static_cast<const DebugBorderDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/debug_border_draw_quad.h b/cc/quads/debug_border_draw_quad.h
index 217c55f..acb80ed 100644
--- a/cc/quads/debug_border_draw_quad.h
+++ b/cc/quads/debug_border_draw_quad.h
@@ -8,12 +8,12 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace cc {
 
-class CC_EXPORT DebugBorderDrawQuad : public DrawQuad {
+class CC_EXPORT DebugBorderDrawQuad : public viz::DrawQuad {
  public:
   DebugBorderDrawQuad();
 
@@ -33,7 +33,7 @@
   SkColor color;
   int width;
 
-  static const DebugBorderDrawQuad* MaterialCast(const DrawQuad*);
+  static const DebugBorderDrawQuad* MaterialCast(const viz::DrawQuad*);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/draw_polygon.cc b/cc/quads/draw_polygon.cc
index 2b664f0..c1375ed 100644
--- a/cc/quads/draw_polygon.cc
+++ b/cc/quads/draw_polygon.cc
@@ -9,7 +9,7 @@
 #include <vector>
 
 #include "base/memory/ptr_util.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 namespace {
 // This threshold controls how "thick" a plane is. If a point's distance is
@@ -34,7 +34,7 @@
 DrawPolygon::DrawPolygon() {
 }
 
-DrawPolygon::DrawPolygon(const DrawQuad* original,
+DrawPolygon::DrawPolygon(const viz::DrawQuad* original,
                          const std::vector<gfx::Point3F>& in_points,
                          const gfx::Vector3dF& normal,
                          int draw_order_index)
@@ -54,7 +54,7 @@
 // This takes the original DrawQuad that this polygon should be based on,
 // a visible content rect to make the 4 corner points from, and a transformation
 // to move it and its normal into screen space.
-DrawPolygon::DrawPolygon(const DrawQuad* original_ref,
+DrawPolygon::DrawPolygon(const viz::DrawQuad* original_ref,
                          const gfx::RectF& visible_layer_rect,
                          const gfx::Transform& transform,
                          int draw_order_index)
diff --git a/cc/quads/draw_polygon.h b/cc/quads/draw_polygon.h
index 34625dc..033706cc 100644
--- a/cc/quads/draw_polygon.h
+++ b/cc/quads/draw_polygon.h
@@ -15,20 +15,22 @@
 #include "ui/gfx/geometry/vector3d_f.h"
 #include "ui/gfx/transform.h"
 
-namespace cc {
-
+namespace viz {
 class DrawQuad;
+}
+
+namespace cc {
 
 class CC_EXPORT DrawPolygon {
  public:
   DrawPolygon();
   ~DrawPolygon();
 
-  DrawPolygon(const DrawQuad* original_ref,
+  DrawPolygon(const viz::DrawQuad* original_ref,
               const std::vector<gfx::Point3F>& in_points,
               const gfx::Vector3dF& normal,
               int draw_order_index = 0);
-  DrawPolygon(const DrawQuad* original_ref,
+  DrawPolygon(const viz::DrawQuad* original_ref,
               const gfx::RectF& visible_layer_rect,
               const gfx::Transform& transform,
               int draw_order_index = 0);
@@ -51,7 +53,7 @@
 
   const std::vector<gfx::Point3F>& points() const { return points_; }
   const gfx::Vector3dF& normal() const { return normal_; }
-  const DrawQuad* original_ref() const { return original_ref_; }
+  const viz::DrawQuad* original_ref() const { return original_ref_; }
   int order_index() const { return order_index_; }
   bool is_split() const { return is_split_; }
   std::unique_ptr<DrawPolygon> CreateCopy();
@@ -78,7 +80,7 @@
   // we need.
   // This DrawQuad is owned by the caller and its lifetime must be preserved
   // as long as this DrawPolygon is alive.
-  const DrawQuad* original_ref_;
+  const viz::DrawQuad* original_ref_;
   bool is_split_;
 };
 
diff --git a/cc/quads/draw_quad_perftest.cc b/cc/quads/draw_quad_perftest.cc
index d0c8540..a3c49cbc 100644
--- a/cc/quads/draw_quad_perftest.cc
+++ b/cc/quads/draw_quad_perftest.cc
@@ -7,9 +7,9 @@
 #include "base/bind.h"
 #include "base/time/time.h"
 #include "cc/base/lap_timer.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass.h"
 #include "cc/quads/texture_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
 
@@ -58,7 +58,7 @@
     shared_state_ = nullptr;
   }
 
-  void GenerateTextureDrawQuads(int count, std::vector<DrawQuad*>* quads) {
+  void GenerateTextureDrawQuads(int count, std::vector<viz::DrawQuad*>* quads) {
     for (int i = 0; i < count; ++i) {
       TextureDrawQuad* quad =
           render_pass_->CreateAndAppendDrawQuad<TextureDrawQuad>();
@@ -83,7 +83,7 @@
 
   void RunIterateResourceTest(const std::string& test_name, int quad_count) {
     CreateRenderPass();
-    std::vector<DrawQuad*> quads;
+    std::vector<viz::DrawQuad*> quads;
     GenerateTextureDrawQuads(quad_count, &quads);
 
     timer_.Reset();
diff --git a/cc/quads/draw_quad_unittest.cc b/cc/quads/draw_quad_unittest.cc
index 000396a..699ae51 100644
--- a/cc/quads/draw_quad_unittest.cc
+++ b/cc/quads/draw_quad_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 #include <stddef.h>
 
@@ -92,7 +92,7 @@
   EXPECT_EQ(source_sqs->sorting_context_id, copy_sqs->sorting_context_id);
 }
 
-void CompareDrawQuad(DrawQuad* quad, DrawQuad* copy) {
+void CompareDrawQuad(viz::DrawQuad* quad, viz::DrawQuad* copy) {
   EXPECT_EQ(quad->material, copy->material);
   EXPECT_EQ(quad->rect, copy->rect);
   EXPECT_EQ(quad->visible_rect, copy->visible_rect);
@@ -114,26 +114,26 @@
   bool needs_blending = true;                  \
   ALLOW_UNUSED_LOCAL(needs_blending);
 
-#define SETUP_AND_COPY_QUAD_NEW(Type, quad)                              \
-  DrawQuad* copy_new = render_pass->CopyFromAndAppendDrawQuad(quad_new); \
-  CompareDrawQuad(quad_new, copy_new);                                   \
-  const Type* copy_quad = Type::MaterialCast(copy_new);                  \
+#define SETUP_AND_COPY_QUAD_NEW(Type, quad)                                   \
+  viz::DrawQuad* copy_new = render_pass->CopyFromAndAppendDrawQuad(quad_new); \
+  CompareDrawQuad(quad_new, copy_new);                                        \
+  const Type* copy_quad = Type::MaterialCast(copy_new);                       \
   ALLOW_UNUSED_LOCAL(copy_quad);
 
-#define SETUP_AND_COPY_QUAD_ALL(Type, quad)                              \
-  DrawQuad* copy_all = render_pass->CopyFromAndAppendDrawQuad(quad_all); \
-  CompareDrawQuad(quad_all, copy_all);                                   \
+#define SETUP_AND_COPY_QUAD_ALL(Type, quad)                                   \
+  viz::DrawQuad* copy_all = render_pass->CopyFromAndAppendDrawQuad(quad_all); \
+  CompareDrawQuad(quad_all, copy_all);                                        \
   copy_quad = Type::MaterialCast(copy_all);
 
 #define SETUP_AND_COPY_QUAD_NEW_RP(Type, quad, a)                    \
-  DrawQuad* copy_new =                                               \
+  viz::DrawQuad* copy_new =                                          \
       render_pass->CopyFromAndAppendRenderPassDrawQuad(quad_new, a); \
   CompareDrawQuad(quad_new, copy_new);                               \
   const Type* copy_quad = Type::MaterialCast(copy_new);              \
   ALLOW_UNUSED_LOCAL(copy_quad);
 
 #define SETUP_AND_COPY_QUAD_ALL_RP(Type, quad, a)                    \
-  DrawQuad* copy_all =                                               \
+  viz::DrawQuad* copy_all =                                          \
       render_pass->CopyFromAndAppendRenderPassDrawQuad(quad_all, a); \
   CompareDrawQuad(quad_all, copy_all);                               \
   copy_quad = Type::MaterialCast(copy_all);
@@ -174,13 +174,13 @@
   CREATE_SHARED_STATE();
 
   CREATE_QUAD_NEW(DebugBorderDrawQuad, visible_rect, color, width);
-  EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::DEBUG_BORDER, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(width, copy_quad->width);
 
   CREATE_QUAD_ALL(DebugBorderDrawQuad, color, width);
-  EXPECT_EQ(DrawQuad::DEBUG_BORDER, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::DEBUG_BORDER, copy_quad->material);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(width, copy_quad->width);
 }
@@ -202,7 +202,7 @@
                      mask_resource_id, mask_uv_rect, mask_texture_size,
                      filters_scale, filters_origin, tex_coord_rect,
                      copied_render_pass_id);
-  EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::RENDER_PASS, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
   EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id());
@@ -216,7 +216,7 @@
   CREATE_QUAD_ALL_RP(RenderPassDrawQuad, render_pass_id, mask_resource_id,
                      mask_uv_rect, mask_texture_size, filters_scale,
                      filters_origin, tex_coord_rect, copied_render_pass_id);
-  EXPECT_EQ(DrawQuad::RENDER_PASS, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::RENDER_PASS, copy_quad->material);
   EXPECT_EQ(copied_render_pass_id, copy_quad->render_pass_id);
   EXPECT_EQ(mask_resource_id, copy_quad->mask_resource_id());
   EXPECT_EQ(mask_uv_rect.ToString(), copy_quad->mask_uv_rect.ToString());
@@ -235,13 +235,13 @@
 
   CREATE_QUAD_NEW(SolidColorDrawQuad, visible_rect, color,
                   force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
 
   CREATE_QUAD_ALL(SolidColorDrawQuad, color, force_anti_aliasing_off);
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::SOLID_COLOR, copy_quad->material);
   EXPECT_EQ(color, copy_quad->color);
   EXPECT_EQ(force_anti_aliasing_off, copy_quad->force_anti_aliasing_off);
 }
@@ -256,7 +256,7 @@
 
   CREATE_QUAD_NEW(StreamVideoDrawQuad, visible_rect, needs_blending,
                   resource_id, resource_size_in_pixels, matrix);
-  EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -265,7 +265,7 @@
 
   CREATE_QUAD_ALL(StreamVideoDrawQuad, resource_id, resource_size_in_pixels,
                   matrix);
-  EXPECT_EQ(DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::STREAM_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(matrix, copy_quad->matrix);
@@ -280,13 +280,13 @@
 
   CREATE_QUAD_NEW(SurfaceDrawQuad, visible_rect, surface_id,
                   SurfaceDrawQuadType::PRIMARY, nullptr);
-  EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::SURFACE_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(surface_id, copy_quad->surface_id);
 
   CREATE_QUAD_ALL(SurfaceDrawQuad, surface_id, SurfaceDrawQuadType::PRIMARY,
                   nullptr);
-  EXPECT_EQ(DrawQuad::SURFACE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::SURFACE_CONTENT, copy_quad->material);
   EXPECT_EQ(surface_id, copy_quad->surface_id);
 }
 
@@ -309,7 +309,7 @@
                   premultiplied_alpha, uv_top_left, uv_bottom_right,
                   SK_ColorTRANSPARENT, vertex_opacity, y_flipped,
                   nearest_neighbor, secure_output_only);
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -325,7 +325,7 @@
                   premultiplied_alpha, uv_top_left, uv_bottom_right,
                   SK_ColorTRANSPARENT, vertex_opacity, y_flipped,
                   nearest_neighbor, secure_output_only);
-  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::TEXTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(resource_size_in_pixels, copy_quad->resource_size_in_pixels());
   EXPECT_EQ(premultiplied_alpha, copy_quad->premultiplied_alpha);
@@ -350,7 +350,7 @@
   CREATE_QUAD_NEW(TileDrawQuad, visible_rect, needs_blending, resource_id,
                   tex_coord_rect, texture_size, swizzle_contents,
                   nearest_neighbor);
-  EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::TILED_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
@@ -361,7 +361,7 @@
 
   CREATE_QUAD_ALL(TileDrawQuad, resource_id, tex_coord_rect, texture_size,
                   swizzle_contents, nearest_neighbor);
-  EXPECT_EQ(DrawQuad::TILED_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::TILED_CONTENT, copy_quad->material);
   EXPECT_EQ(resource_id, copy_quad->resource_id());
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
@@ -394,7 +394,7 @@
                   v_plane_resource_id, a_plane_resource_id, color_space,
                   video_color_space, resource_offset, resource_multiplier,
                   bits_per_channel);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
@@ -416,7 +416,7 @@
                   u_plane_resource_id, v_plane_resource_id, a_plane_resource_id,
                   color_space, video_color_space, resource_offset,
                   resource_multiplier, bits_per_channel, require_overlay);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(ya_tex_coord_rect, copy_quad->ya_tex_coord_rect);
   EXPECT_EQ(uv_tex_coord_rect, copy_quad->uv_tex_coord_rect);
   EXPECT_EQ(ya_tex_size, copy_quad->ya_tex_size);
@@ -448,7 +448,7 @@
   CREATE_QUAD_NEW(PictureDrawQuad, visible_rect, needs_blending, tex_coord_rect,
                   texture_size, nearest_neighbor, texture_format, content_rect,
                   contents_scale, raster_source);
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(visible_rect, copy_quad->visible_rect);
   EXPECT_EQ(needs_blending, copy_quad->needs_blending);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
@@ -462,7 +462,7 @@
   CREATE_QUAD_ALL(PictureDrawQuad, tex_coord_rect, texture_size,
                   nearest_neighbor, texture_format, content_rect,
                   contents_scale, raster_source);
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::PICTURE_CONTENT, copy_quad->material);
   EXPECT_EQ(tex_coord_rect, copy_quad->tex_coord_rect);
   EXPECT_EQ(texture_size, copy_quad->texture_size);
   EXPECT_EQ(nearest_neighbor, copy_quad->nearest_neighbor);
@@ -474,7 +474,7 @@
 
 class DrawQuadIteratorTest : public testing::Test {
  protected:
-  int IterateAndCount(DrawQuad* quad) {
+  int IterateAndCount(viz::DrawQuad* quad) {
     num_resources_ = 0;
     for (viz::ResourceId& resource_id : quad->resources) {
       ++num_resources_;
@@ -622,7 +622,7 @@
                   uv_tex_size, y_plane_resource_id, u_plane_resource_id,
                   v_plane_resource_id, a_plane_resource_id, color_space,
                   video_color_space, 0.0, 1.0, 5);
-  EXPECT_EQ(DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
+  EXPECT_EQ(viz::DrawQuad::YUV_VIDEO_CONTENT, copy_quad->material);
   EXPECT_EQ(y_plane_resource_id, quad_new->y_plane_resource_id());
   EXPECT_EQ(u_plane_resource_id, quad_new->u_plane_resource_id());
   EXPECT_EQ(v_plane_resource_id, quad_new->v_plane_resource_id());
@@ -657,36 +657,36 @@
 TEST(DrawQuadTest, LargestQuadType) {
   size_t largest = 0;
 
-  for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) {
-    switch (static_cast<DrawQuad::Material>(i)) {
-      case DrawQuad::DEBUG_BORDER:
+  for (int i = 0; i <= viz::DrawQuad::MATERIAL_LAST; ++i) {
+    switch (static_cast<viz::DrawQuad::Material>(i)) {
+      case viz::DrawQuad::DEBUG_BORDER:
         largest = std::max(largest, sizeof(DebugBorderDrawQuad));
         break;
-      case DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         largest = std::max(largest, sizeof(PictureDrawQuad));
         break;
-      case DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         largest = std::max(largest, sizeof(TextureDrawQuad));
         break;
-      case DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         largest = std::max(largest, sizeof(RenderPassDrawQuad));
         break;
-      case DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         largest = std::max(largest, sizeof(SolidColorDrawQuad));
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         largest = std::max(largest, sizeof(SurfaceDrawQuad));
         break;
-      case DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         largest = std::max(largest, sizeof(TileDrawQuad));
         break;
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         largest = std::max(largest, sizeof(StreamVideoDrawQuad));
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         largest = std::max(largest, sizeof(YUVVideoDrawQuad));
         break;
-      case DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
   }
@@ -698,36 +698,36 @@
   // On failure, output the size of all quads for debugging.
   LOG(ERROR) << "largest " << largest;
   LOG(ERROR) << "kLargestDrawQuad " << LargestDrawQuadSize();
-  for (int i = 0; i <= DrawQuad::MATERIAL_LAST; ++i) {
-    switch (static_cast<DrawQuad::Material>(i)) {
-      case DrawQuad::DEBUG_BORDER:
+  for (int i = 0; i <= viz::DrawQuad::MATERIAL_LAST; ++i) {
+    switch (static_cast<viz::DrawQuad::Material>(i)) {
+      case viz::DrawQuad::DEBUG_BORDER:
         LOG(ERROR) << "DebugBorderDrawQuad " << sizeof(DebugBorderDrawQuad);
         break;
-      case DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         LOG(ERROR) << "PictureDrawQuad " << sizeof(PictureDrawQuad);
         break;
-      case DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         LOG(ERROR) << "TextureDrawQuad " << sizeof(TextureDrawQuad);
         break;
-      case DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         LOG(ERROR) << "RenderPassDrawQuad " << sizeof(RenderPassDrawQuad);
         break;
-      case DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         LOG(ERROR) << "SolidColorDrawQuad " << sizeof(SolidColorDrawQuad);
         break;
-      case DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         LOG(ERROR) << "SurfaceDrawQuad " << sizeof(SurfaceDrawQuad);
         break;
-      case DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         LOG(ERROR) << "TileDrawQuad " << sizeof(TileDrawQuad);
         break;
-      case DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         LOG(ERROR) << "StreamVideoDrawQuad " << sizeof(StreamVideoDrawQuad);
         break;
-      case DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         LOG(ERROR) << "YUVVideoDrawQuad " << sizeof(YUVVideoDrawQuad);
         break;
-      case DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
     }
   }
diff --git a/cc/quads/picture_draw_quad.cc b/cc/quads/picture_draw_quad.cc
index ec57c52e..e9f45cc 100644
--- a/cc/quads/picture_draw_quad.cc
+++ b/cc/quads/picture_draw_quad.cc
@@ -31,7 +31,7 @@
                              float contents_scale,
                              scoped_refptr<RasterSource> raster_source) {
   ContentDrawQuadBase::SetNew(
-      shared_quad_state, DrawQuad::PICTURE_CONTENT, rect, visible_rect,
+      shared_quad_state, viz::DrawQuad::PICTURE_CONTENT, rect, visible_rect,
       needs_blending, tex_coord_rect, texture_size,
       !viz::PlatformColor::SameComponentOrder(texture_format),
       nearest_neighbor);
@@ -53,7 +53,7 @@
                              float contents_scale,
                              scoped_refptr<RasterSource> raster_source) {
   ContentDrawQuadBase::SetAll(
-      shared_quad_state, DrawQuad::PICTURE_CONTENT, rect, visible_rect,
+      shared_quad_state, viz::DrawQuad::PICTURE_CONTENT, rect, visible_rect,
       needs_blending, tex_coord_rect, texture_size,
       !viz::PlatformColor::SameComponentOrder(texture_format),
       nearest_neighbor);
@@ -63,8 +63,9 @@
   this->texture_format = texture_format;
 }
 
-const PictureDrawQuad* PictureDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::PICTURE_CONTENT);
+const PictureDrawQuad* PictureDrawQuad::MaterialCast(
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::PICTURE_CONTENT);
   return static_cast<const PictureDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/picture_draw_quad.h b/cc/quads/picture_draw_quad.h
index 02e7607..34c833e1 100644
--- a/cc/quads/picture_draw_quad.h
+++ b/cc/quads/picture_draw_quad.h
@@ -54,7 +54,7 @@
   scoped_refptr<RasterSource> raster_source;
   viz::ResourceFormat texture_format;
 
-  static const PictureDrawQuad* MaterialCast(const DrawQuad* quad);
+  static const PictureDrawQuad* MaterialCast(const viz::DrawQuad* quad);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/render_pass.cc b/cc/quads/render_pass.cc
index 4955f0b..da69654 100644
--- a/cc/quads/render_pass.cc
+++ b/cc/quads/render_pass.cc
@@ -15,7 +15,6 @@
 #include "base/values.h"
 #include "cc/base/math_util.h"
 #include "cc/quads/debug_border_draw_quad.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/largest_draw_quad.h"
 #include "cc/quads/picture_draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
@@ -26,6 +25,7 @@
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/quads/yuv_video_draw_quad.h"
 #include "components/viz/common/quads/copy_output_request.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "components/viz/common/traced_value.h"
 
@@ -37,14 +37,14 @@
 namespace cc {
 
 QuadList::QuadList()
-    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
-                              LargestDrawQuadSize(),
-                              kDefaultNumSharedQuadStatesToReserve) {}
+    : ListContainer<viz::DrawQuad>(LargestDrawQuadAlignment(),
+                                   LargestDrawQuadSize(),
+                                   kDefaultNumSharedQuadStatesToReserve) {}
 
 QuadList::QuadList(size_t default_size_to_reserve)
-    : ListContainer<DrawQuad>(LargestDrawQuadAlignment(),
-                              LargestDrawQuadSize(),
-                              default_size_to_reserve) {}
+    : ListContainer<viz::DrawQuad>(LargestDrawQuadAlignment(),
+                                   LargestDrawQuadSize(),
+                                   default_size_to_reserve) {}
 
 void QuadList::ReplaceExistingQuadWithOpaqueTransparentSolidColor(Iterator at) {
   // In order to fill the backbuffer with transparent black, the replacement
@@ -148,7 +148,7 @@
     }
     DCHECK(quad->shared_quad_state == *sqs_iter);
 
-    if (quad->material == DrawQuad::RENDER_PASS) {
+    if (quad->material == viz::DrawQuad::RENDER_PASS) {
       const RenderPassDrawQuad* pass_quad =
           RenderPassDrawQuad::MaterialCast(quad);
       copy_pass->CopyFromAndAppendRenderPassDrawQuad(pass_quad,
@@ -268,36 +268,37 @@
   return copy_quad;
 }
 
-DrawQuad* RenderPass::CopyFromAndAppendDrawQuad(const DrawQuad* quad) {
+viz::DrawQuad* RenderPass::CopyFromAndAppendDrawQuad(
+    const viz::DrawQuad* quad) {
   DCHECK(!shared_quad_state_list.empty());
   switch (quad->material) {
-    case DrawQuad::DEBUG_BORDER:
+    case viz::DrawQuad::DEBUG_BORDER:
       CopyFromAndAppendTypedDrawQuad<DebugBorderDrawQuad>(quad);
       break;
-    case DrawQuad::PICTURE_CONTENT:
+    case viz::DrawQuad::PICTURE_CONTENT:
       CopyFromAndAppendTypedDrawQuad<PictureDrawQuad>(quad);
       break;
-    case DrawQuad::TEXTURE_CONTENT:
+    case viz::DrawQuad::TEXTURE_CONTENT:
       CopyFromAndAppendTypedDrawQuad<TextureDrawQuad>(quad);
       break;
-    case DrawQuad::SOLID_COLOR:
+    case viz::DrawQuad::SOLID_COLOR:
       CopyFromAndAppendTypedDrawQuad<SolidColorDrawQuad>(quad);
       break;
-    case DrawQuad::TILED_CONTENT:
+    case viz::DrawQuad::TILED_CONTENT:
       CopyFromAndAppendTypedDrawQuad<TileDrawQuad>(quad);
       break;
-    case DrawQuad::STREAM_VIDEO_CONTENT:
+    case viz::DrawQuad::STREAM_VIDEO_CONTENT:
       CopyFromAndAppendTypedDrawQuad<StreamVideoDrawQuad>(quad);
       break;
-    case DrawQuad::SURFACE_CONTENT:
+    case viz::DrawQuad::SURFACE_CONTENT:
       CopyFromAndAppendTypedDrawQuad<SurfaceDrawQuad>(quad);
       break;
-    case DrawQuad::YUV_VIDEO_CONTENT:
+    case viz::DrawQuad::YUV_VIDEO_CONTENT:
       CopyFromAndAppendTypedDrawQuad<YUVVideoDrawQuad>(quad);
       break;
     // RenderPass quads need to use specific CopyFrom function.
-    case DrawQuad::RENDER_PASS:
-    case DrawQuad::INVALID:
+    case viz::DrawQuad::RENDER_PASS:
+    case viz::DrawQuad::INVALID:
       LOG(FATAL) << "Invalid DrawQuad material " << quad->material;
       break;
   }
diff --git a/cc/quads/render_pass.h b/cc/quads/render_pass.h
index 35ff6f1..c0109332 100644
--- a/cc/quads/render_pass.h
+++ b/cc/quads/render_pass.h
@@ -16,8 +16,8 @@
 #include "cc/base/filter_operations.h"
 #include "cc/base/list_container.h"
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/largest_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect.h"
 #include "ui/gfx/geometry/rect_f.h"
@@ -31,16 +31,16 @@
 
 namespace viz {
 class CopyOutputRequest;
+class DrawQuad;
 class SharedQuadState;
 }
 
 namespace cc {
 
-class DrawQuad;
 class RenderPassDrawQuad;
 
 // A list of DrawQuad objects, sorted internally in front-to-back order.
-class CC_EXPORT QuadList : public ListContainer<DrawQuad> {
+class CC_EXPORT QuadList : public ListContainer<viz::DrawQuad> {
  public:
   QuadList();
   explicit QuadList(size_t default_size_to_reserve);
@@ -110,7 +110,7 @@
   RenderPassDrawQuad* CopyFromAndAppendRenderPassDrawQuad(
       const RenderPassDrawQuad* quad,
       RenderPassId render_pass_id);
-  DrawQuad* CopyFromAndAppendDrawQuad(const DrawQuad* quad);
+  viz::DrawQuad* CopyFromAndAppendDrawQuad(const viz::DrawQuad* quad);
 
   // Uniquely identifies the render pass in the compositor's current frame.
   RenderPassId id = 0;
@@ -158,7 +158,7 @@
 
  private:
   template <typename DrawQuadType>
-  DrawQuadType* CopyFromAndAppendTypedDrawQuad(const DrawQuad* quad) {
+  DrawQuadType* CopyFromAndAppendTypedDrawQuad(const viz::DrawQuad* quad) {
     return quad_list.AllocateAndCopyFrom(DrawQuadType::MaterialCast(quad));
   }
 
diff --git a/cc/quads/render_pass_draw_quad.cc b/cc/quads/render_pass_draw_quad.cc
index 9a657a6..72bf345 100644
--- a/cc/quads/render_pass_draw_quad.cc
+++ b/cc/quads/render_pass_draw_quad.cc
@@ -52,8 +52,8 @@
                                 const gfx::RectF& tex_coord_rect) {
   DCHECK(render_pass_id);
 
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::RENDER_PASS, rect, visible_rect,
-                   needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::RENDER_PASS, rect,
+                        visible_rect, needs_blending);
   this->render_pass_id = render_pass_id;
   resources.ids[kMaskResourceIdIndex] = mask_resource_id;
   resources.count = mask_resource_id ? 1 : 0;
@@ -65,8 +65,8 @@
 }
 
 const RenderPassDrawQuad* RenderPassDrawQuad::MaterialCast(
-    const DrawQuad* quad) {
-  DCHECK_EQ(quad->material, DrawQuad::RENDER_PASS);
+    const viz::DrawQuad* quad) {
+  DCHECK_EQ(quad->material, viz::DrawQuad::RENDER_PASS);
   return static_cast<const RenderPassDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/render_pass_draw_quad.h b/cc/quads/render_pass_draw_quad.h
index 929bf7ec..cc76f18 100644
--- a/cc/quads/render_pass_draw_quad.h
+++ b/cc/quads/render_pass_draw_quad.h
@@ -11,15 +11,15 @@
 
 #include "cc/base/filter_operations.h"
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 #include "ui/gfx/geometry/point_f.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace cc {
 
-class CC_EXPORT RenderPassDrawQuad : public DrawQuad {
+class CC_EXPORT RenderPassDrawQuad : public viz::DrawQuad {
  public:
   static const size_t kMaskResourceIdIndex = 0;
 
@@ -70,7 +70,7 @@
     return resources.ids[kMaskResourceIdIndex];
   }
 
-  static const RenderPassDrawQuad* MaterialCast(const DrawQuad*);
+  static const RenderPassDrawQuad* MaterialCast(const viz::DrawQuad*);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/solid_color_draw_quad.cc b/cc/quads/solid_color_draw_quad.cc
index 03a82af..f25b226 100644
--- a/cc/quads/solid_color_draw_quad.cc
+++ b/cc/quads/solid_color_draw_quad.cc
@@ -19,8 +19,8 @@
                                 SkColor color,
                                 bool force_anti_aliasing_off) {
   bool needs_blending = SkColorGetA(color) != 255;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SOLID_COLOR, rect, visible_rect,
-                   needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::SOLID_COLOR, rect,
+                        visible_rect, needs_blending);
   this->color = color;
   this->force_anti_aliasing_off = force_anti_aliasing_off;
 }
@@ -31,15 +31,15 @@
                                 bool needs_blending,
                                 SkColor color,
                                 bool force_anti_aliasing_off) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SOLID_COLOR, rect, visible_rect,
-                   needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::SOLID_COLOR, rect,
+                        visible_rect, needs_blending);
   this->color = color;
   this->force_anti_aliasing_off = force_anti_aliasing_off;
 }
 
 const SolidColorDrawQuad* SolidColorDrawQuad::MaterialCast(
-    const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::SOLID_COLOR);
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::SOLID_COLOR);
   return static_cast<const SolidColorDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/solid_color_draw_quad.h b/cc/quads/solid_color_draw_quad.h
index 75f7e97c4..a065c03 100644
--- a/cc/quads/solid_color_draw_quad.h
+++ b/cc/quads/solid_color_draw_quad.h
@@ -8,12 +8,12 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "third_party/skia/include/core/SkColor.h"
 
 namespace cc {
 
-class CC_EXPORT SolidColorDrawQuad : public DrawQuad {
+class CC_EXPORT SolidColorDrawQuad : public viz::DrawQuad {
  public:
   SolidColorDrawQuad();
 
@@ -33,7 +33,7 @@
   SkColor color;
   bool force_anti_aliasing_off;
 
-  static const SolidColorDrawQuad* MaterialCast(const DrawQuad*);
+  static const SolidColorDrawQuad* MaterialCast(const viz::DrawQuad*);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/stream_video_draw_quad.cc b/cc/quads/stream_video_draw_quad.cc
index 08fc1f55..dfb358f 100644
--- a/cc/quads/stream_video_draw_quad.cc
+++ b/cc/quads/stream_video_draw_quad.cc
@@ -21,8 +21,8 @@
                                  unsigned resource_id,
                                  gfx::Size resource_size_in_pixels,
                                  const gfx::Transform& matrix) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::STREAM_VIDEO_CONTENT,
+                        rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
   resources.count = 1;
@@ -36,8 +36,8 @@
                                  unsigned resource_id,
                                  gfx::Size resource_size_in_pixels,
                                  const gfx::Transform& matrix) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::STREAM_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::STREAM_VIDEO_CONTENT,
+                        rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
   resources.count = 1;
@@ -45,8 +45,8 @@
 }
 
 const StreamVideoDrawQuad* StreamVideoDrawQuad::MaterialCast(
-    const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::STREAM_VIDEO_CONTENT);
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::STREAM_VIDEO_CONTENT);
   return static_cast<const StreamVideoDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/stream_video_draw_quad.h b/cc/quads/stream_video_draw_quad.h
index 44a2013f..2bb253ff 100644
--- a/cc/quads/stream_video_draw_quad.h
+++ b/cc/quads/stream_video_draw_quad.h
@@ -10,12 +10,12 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/transform.h"
 
 namespace cc {
 
-class CC_EXPORT StreamVideoDrawQuad : public DrawQuad {
+class CC_EXPORT StreamVideoDrawQuad : public viz::DrawQuad {
  public:
   static const size_t kResourceIdIndex = 0;
 
@@ -45,7 +45,7 @@
   };
   OverlayResources overlay_resources;
 
-  static const StreamVideoDrawQuad* MaterialCast(const DrawQuad*);
+  static const StreamVideoDrawQuad* MaterialCast(const viz::DrawQuad*);
 
   viz::ResourceId resource_id() const {
     return resources.ids[kResourceIdIndex];
diff --git a/cc/quads/surface_draw_quad.cc b/cc/quads/surface_draw_quad.cc
index 03ddfbf..4e57d79 100644
--- a/cc/quads/surface_draw_quad.cc
+++ b/cc/quads/surface_draw_quad.cc
@@ -20,8 +20,8 @@
                              SurfaceDrawQuadType surface_draw_quad_type,
                              SurfaceDrawQuad* fallback_quad) {
   bool needs_blending = true;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::SURFACE_CONTENT, rect,
+                        visible_rect, needs_blending);
   this->surface_id = surface_id;
   this->surface_draw_quad_type = surface_draw_quad_type;
   this->fallback_quad = fallback_quad;
@@ -34,15 +34,16 @@
                              const viz::SurfaceId& surface_id,
                              SurfaceDrawQuadType surface_draw_quad_type,
                              SurfaceDrawQuad* fallback_quad) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::SURFACE_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::SURFACE_CONTENT, rect,
+                        visible_rect, needs_blending);
   this->surface_id = surface_id;
   this->surface_draw_quad_type = surface_draw_quad_type;
   this->fallback_quad = fallback_quad;
 }
 
-const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK_EQ(quad->material, DrawQuad::SURFACE_CONTENT);
+const SurfaceDrawQuad* SurfaceDrawQuad::MaterialCast(
+    const viz::DrawQuad* quad) {
+  DCHECK_EQ(quad->material, viz::DrawQuad::SURFACE_CONTENT);
   return static_cast<const SurfaceDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/surface_draw_quad.h b/cc/quads/surface_draw_quad.h
index bcab58e..e376791 100644
--- a/cc/quads/surface_draw_quad.h
+++ b/cc/quads/surface_draw_quad.h
@@ -8,14 +8,14 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/surfaces/surface_id.h"
 
 namespace cc {
 
 enum class SurfaceDrawQuadType { PRIMARY, FALLBACK, LAST = FALLBACK };
 
-class CC_EXPORT SurfaceDrawQuad : public DrawQuad {
+class CC_EXPORT SurfaceDrawQuad : public viz::DrawQuad {
  public:
   SurfaceDrawQuad();
 
@@ -38,7 +38,7 @@
   SurfaceDrawQuadType surface_draw_quad_type;
   const SurfaceDrawQuad* fallback_quad = nullptr;
 
-  static const SurfaceDrawQuad* MaterialCast(const DrawQuad* quad);
+  static const SurfaceDrawQuad* MaterialCast(const viz::DrawQuad* quad);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/texture_draw_quad.cc b/cc/quads/texture_draw_quad.cc
index 2f1bfad..3c43c72 100644
--- a/cc/quads/texture_draw_quad.cc
+++ b/cc/quads/texture_draw_quad.cc
@@ -43,8 +43,8 @@
   needs_blending = needs_blending || vertex_opacity[0] != 1.0f ||
                    vertex_opacity[1] != 1.0f || vertex_opacity[2] != 1.0f ||
                    vertex_opacity[3] != 1.0f;
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::TEXTURE_CONTENT, rect,
+                        visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
   this->premultiplied_alpha = premultiplied_alpha;
@@ -74,8 +74,8 @@
                              bool y_flipped,
                              bool nearest_neighbor,
                              bool secure_output_only) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::TEXTURE_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::TEXTURE_CONTENT, rect,
+                        visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
   overlay_resources.size_in_pixels[kResourceIdIndex] = resource_size_in_pixels;
   resources.count = 1;
@@ -92,8 +92,9 @@
   this->secure_output_only = secure_output_only;
 }
 
-const TextureDrawQuad* TextureDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::TEXTURE_CONTENT);
+const TextureDrawQuad* TextureDrawQuad::MaterialCast(
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::TEXTURE_CONTENT);
   return static_cast<const TextureDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/texture_draw_quad.h b/cc/quads/texture_draw_quad.h
index c2f4b6ec..e76824c7 100644
--- a/cc/quads/texture_draw_quad.h
+++ b/cc/quads/texture_draw_quad.h
@@ -10,13 +10,13 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "third_party/skia/include/core/SkColor.h"
 #include "ui/gfx/geometry/rect_f.h"
 
 namespace cc {
 
-class CC_EXPORT TextureDrawQuad : public DrawQuad {
+class CC_EXPORT TextureDrawQuad : public viz::DrawQuad {
  public:
   static const size_t kResourceIdIndex = 0;
 
@@ -78,7 +78,7 @@
     overlay_resources.size_in_pixels[kResourceIdIndex] = size_in_pixels;
   }
 
-  static const TextureDrawQuad* MaterialCast(const DrawQuad*);
+  static const TextureDrawQuad* MaterialCast(const viz::DrawQuad*);
 
  private:
   void ExtendValue(base::trace_event::TracedValue* value) const override;
diff --git a/cc/quads/tile_draw_quad.cc b/cc/quads/tile_draw_quad.cc
index 1ac34fb..1a5a602 100644
--- a/cc/quads/tile_draw_quad.cc
+++ b/cc/quads/tile_draw_quad.cc
@@ -25,9 +25,10 @@
                           const gfx::Size& texture_size,
                           bool swizzle_contents,
                           bool nearest_neighbor) {
-  ContentDrawQuadBase::SetNew(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
-                              visible_rect, needs_blending, tex_coord_rect,
-                              texture_size, swizzle_contents, nearest_neighbor);
+  ContentDrawQuadBase::SetNew(shared_quad_state, viz::DrawQuad::TILED_CONTENT,
+                              rect, visible_rect, needs_blending,
+                              tex_coord_rect, texture_size, swizzle_contents,
+                              nearest_neighbor);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
 }
@@ -41,15 +42,16 @@
                           const gfx::Size& texture_size,
                           bool swizzle_contents,
                           bool nearest_neighbor) {
-  ContentDrawQuadBase::SetAll(shared_quad_state, DrawQuad::TILED_CONTENT, rect,
-                              visible_rect, needs_blending, tex_coord_rect,
-                              texture_size, swizzle_contents, nearest_neighbor);
+  ContentDrawQuadBase::SetAll(shared_quad_state, viz::DrawQuad::TILED_CONTENT,
+                              rect, visible_rect, needs_blending,
+                              tex_coord_rect, texture_size, swizzle_contents,
+                              nearest_neighbor);
   resources.ids[kResourceIdIndex] = resource_id;
   resources.count = 1;
 }
 
-const TileDrawQuad* TileDrawQuad::MaterialCast(const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::TILED_CONTENT);
+const TileDrawQuad* TileDrawQuad::MaterialCast(const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::TILED_CONTENT);
   return static_cast<const TileDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/tile_draw_quad.h b/cc/quads/tile_draw_quad.h
index 1c490f34e..a3f226bb 100644
--- a/cc/quads/tile_draw_quad.h
+++ b/cc/quads/tile_draw_quad.h
@@ -44,7 +44,7 @@
               bool swizzle_contents,
               bool nearest_neighbor);
 
-  static const TileDrawQuad* MaterialCast(const DrawQuad*);
+  static const TileDrawQuad* MaterialCast(const viz::DrawQuad*);
 
   viz::ResourceId resource_id() const {
     return resources.ids[kResourceIdIndex];
diff --git a/cc/quads/yuv_video_draw_quad.cc b/cc/quads/yuv_video_draw_quad.cc
index d666030..5b4f39fa 100644
--- a/cc/quads/yuv_video_draw_quad.cc
+++ b/cc/quads/yuv_video_draw_quad.cc
@@ -35,8 +35,8 @@
                               float offset,
                               float multiplier,
                               uint32_t bits_per_channel) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::YUV_VIDEO_CONTENT,
+                        rect, visible_rect, needs_blending);
   this->ya_tex_coord_rect = ya_tex_coord_rect;
   this->uv_tex_coord_rect = uv_tex_coord_rect;
   this->ya_tex_size = ya_tex_size;
@@ -71,8 +71,8 @@
                               float multiplier,
                               uint32_t bits_per_channel,
                               bool require_overlay) {
-  DrawQuad::SetAll(shared_quad_state, DrawQuad::YUV_VIDEO_CONTENT, rect,
-                   visible_rect, needs_blending);
+  viz::DrawQuad::SetAll(shared_quad_state, viz::DrawQuad::YUV_VIDEO_CONTENT,
+                        rect, visible_rect, needs_blending);
   this->ya_tex_coord_rect = ya_tex_coord_rect;
   this->uv_tex_coord_rect = uv_tex_coord_rect;
   this->ya_tex_size = ya_tex_size;
@@ -91,8 +91,8 @@
 }
 
 const YUVVideoDrawQuad* YUVVideoDrawQuad::MaterialCast(
-    const DrawQuad* quad) {
-  DCHECK(quad->material == DrawQuad::YUV_VIDEO_CONTENT);
+    const viz::DrawQuad* quad) {
+  DCHECK(quad->material == viz::DrawQuad::YUV_VIDEO_CONTENT);
   return static_cast<const YUVVideoDrawQuad*>(quad);
 }
 
diff --git a/cc/quads/yuv_video_draw_quad.h b/cc/quads/yuv_video_draw_quad.h
index 2545b87..612e631 100644
--- a/cc/quads/yuv_video_draw_quad.h
+++ b/cc/quads/yuv_video_draw_quad.h
@@ -10,14 +10,14 @@
 #include <memory>
 
 #include "cc/cc_export.h"
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/rect_f.h"
 #include "ui/gfx/geometry/size.h"
 
 namespace cc {
 
-class CC_EXPORT YUVVideoDrawQuad : public DrawQuad {
+class CC_EXPORT YUVVideoDrawQuad : public viz::DrawQuad {
  public:
   static const size_t kYPlaneResourceIdIndex = 0;
   static const size_t kUPlaneResourceIdIndex = 1;
@@ -93,7 +93,7 @@
   gfx::ColorSpace video_color_space;
   bool require_overlay = false;
 
-  static const YUVVideoDrawQuad* MaterialCast(const DrawQuad*);
+  static const YUVVideoDrawQuad* MaterialCast(const viz::DrawQuad*);
 
   viz::ResourceId y_plane_resource_id() const {
     return resources.ids[kYPlaneResourceIdIndex];
diff --git a/cc/test/layer_test_common.cc b/cc/test/layer_test_common.cc
index 5bf5e48..a6fe62d 100644
--- a/cc/test/layer_test_common.cc
+++ b/cc/test/layer_test_common.cc
@@ -12,7 +12,6 @@
 #include "cc/base/math_util.h"
 #include "cc/base/region.h"
 #include "cc/layers/append_quads_data.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass.h"
 #include "cc/test/animation_test_common.h"
 #include "cc/test/fake_layer_tree_frame_sink.h"
@@ -20,6 +19,7 @@
 #include "cc/trees/layer_tree_host_common.h"
 #include "components/viz/common/quads/copy_output_request.h"
 #include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/geometry/point_conversions.h"
 #include "ui/gfx/geometry/rect.h"
diff --git a/cc/tiles/software_image_decode_cache.cc b/cc/tiles/software_image_decode_cache.cc
index b9e3f75..3458e5c 100644
--- a/cc/tiles/software_image_decode_cache.cc
+++ b/cc/tiles/software_image_decode_cache.cc
@@ -452,12 +452,15 @@
   // that scale, or
   // - If we're not doing a scale at all (which is supported by all decoders and
   // subsetting is handled in the draw calls).
-  // TODO(vmpstr): See if we can subrect thing decoded to native scale.
+  // TODO(vmpstr): See if we can subrect the result of decoded to scale.
   SkIRect full_size_rect =
       SkIRect::MakeWH(paint_image.width(), paint_image.height());
   bool need_subset = (gfx::RectToSkIRect(key.src_rect()) != full_size_rect);
   SkISize exact_size =
       SkISize::Make(key.target_size().width(), key.target_size().height());
+  // TODO(vmpstr): If an image of a bigger size is already decoded and is
+  // lock-able then it might be faster to just scale that instead of redecoding
+  // to exact scale. We need to profile this.
   if ((!need_subset &&
        exact_size == paint_image.GetSupportedDecodeSize(exact_size)) ||
       SkIRect::MakeSize(exact_size) == full_size_rect) {
@@ -994,6 +997,10 @@
   } else {
     quality = kMedium_SkFilterQuality;
     // Update the target size to be a mip level size.
+    // TODO(vmpstr): MipMapUtil and JPEG decoders disagree on what to do with
+    // odd sizes. If width = 2k + 1, and the mip level is 1, then this will
+    // return width = k; JPEG decoder, however, will support decoding to width =
+    // k + 1. We need to figure out what to do in this case.
     SkSize mip_scale_adjustment =
         MipMapUtil::GetScaleAdjustmentForLevel(src_rect.size(), mip_level);
     target_size.set_width(src_rect.width() * mip_scale_adjustment.width());
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 769010a..3a33775 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -1182,7 +1182,7 @@
 
     // Remove orphan RenderPassDrawQuads.
     for (auto it = pass->quad_list.begin(); it != pass->quad_list.end();) {
-      if (it->material != DrawQuad::RENDER_PASS) {
+      if (it->material != viz::DrawQuad::RENDER_PASS) {
         ++it;
         continue;
       }
@@ -1229,7 +1229,7 @@
       continue;
 
     for (auto it = pass->quad_list.begin(); it != pass->quad_list.end(); ++it) {
-      if (it->material != DrawQuad::RENDER_PASS)
+      if (it->material != viz::DrawQuad::RENDER_PASS)
         continue;
       const RenderPassDrawQuad* quad = RenderPassDrawQuad::MaterialCast(*it);
       pass_references[quad->render_pass_id]--;
diff --git a/cc/trees/layer_tree_host_impl_unittest.cc b/cc/trees/layer_tree_host_impl_unittest.cc
index 0becf135..a25d09d 100644
--- a/cc/trees/layer_tree_host_impl_unittest.cc
+++ b/cc/trees/layer_tree_host_impl_unittest.cc
@@ -8158,7 +8158,7 @@
 class LayerTreeHostImplViewportCoveredTest : public LayerTreeHostImplTest {
  protected:
   LayerTreeHostImplViewportCoveredTest()
-      : gutter_quad_material_(DrawQuad::SOLID_COLOR),
+      : gutter_quad_material_(viz::DrawQuad::SOLID_COLOR),
         child_(NULL),
         did_activate_pending_tree_(false) {}
 
@@ -8324,7 +8324,7 @@
 
   void DidActivateSyncTree() override { did_activate_pending_tree_ = true; }
 
-  void set_gutter_quad_material(DrawQuad::Material material) {
+  void set_gutter_quad_material(viz::DrawQuad::Material material) {
     gutter_quad_material_ = material;
   }
   void set_gutter_texture_size(const gfx::Size& gutter_texture_size) {
@@ -8348,7 +8348,7 @@
   // Make sure that the texture coordinates match their expectations.
   void ValidateTextureDrawQuads(const QuadList& quad_list) {
     for (auto* quad : quad_list) {
-      if (quad->material != DrawQuad::TEXTURE_CONTENT)
+      if (quad->material != viz::DrawQuad::TEXTURE_CONTENT)
         continue;
       const TextureDrawQuad* texture_quad = TextureDrawQuad::MaterialCast(quad);
       gfx::SizeF gutter_texture_size_pixels =
@@ -8372,7 +8372,7 @@
         size, host_impl_->active_tree()->device_scale_factor());
   }
 
-  DrawQuad::Material gutter_quad_material_;
+  viz::DrawQuad::Material gutter_quad_material_;
   gfx::Size gutter_texture_size_;
   gfx::Size viewport_size_;
   BlendStateCheckLayer* child_;
@@ -8662,7 +8662,8 @@
   {
     const auto& root_pass = frame.render_passes.back();
     ASSERT_EQ(1u, root_pass->quad_list.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.front()->material);
   }
   host_impl_->DrawLayers(&frame);
   host_impl_->DidDrawAllLayers(frame);
@@ -8829,7 +8830,7 @@
 
   ASSERT_EQ(1u, frame.render_passes.size());
   ASSERT_LE(1u, frame.render_passes[0]->quad_list.size());
-  const DrawQuad* quad = frame.render_passes[0]->quad_list.front();
+  const viz::DrawQuad* quad = frame.render_passes[0]->quad_list.front();
 
   bool clipped = false, force_aa = false;
   gfx::QuadF device_layer_quad = MathUtil::MapQuad(
@@ -12062,16 +12063,16 @@
   // Add a quad to each pass so they aren't empty.
   SolidColorDrawQuad* color_quad;
   color_quad = pass1->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-  color_quad->material = DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::SOLID_COLOR;
   color_quad = pass2->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-  color_quad->material = DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::SOLID_COLOR;
   color_quad = pass3->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-  color_quad->material = DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::SOLID_COLOR;
 
   // pass3 is referenced by pass2.
   RenderPassDrawQuad* rpdq =
       pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
-  rpdq->material = DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::RENDER_PASS;
   rpdq->render_pass_id = pass3->id;
 
   // But pass2 is not referenced by pass1. So pass2 and pass3 should be culled.
@@ -12099,17 +12100,17 @@
   // pass1 is not empty, but pass2 and pass3 are.
   SolidColorDrawQuad* color_quad;
   color_quad = pass1->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
-  color_quad->material = DrawQuad::SOLID_COLOR;
+  color_quad->material = viz::DrawQuad::SOLID_COLOR;
 
   // pass3 is referenced by pass2.
   RenderPassDrawQuad* rpdq =
       pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
-  rpdq->material = DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::RENDER_PASS;
   rpdq->render_pass_id = pass3->id;
 
   // pass2 is referenced by pass1.
   rpdq = pass1->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
-  rpdq->material = DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::RENDER_PASS;
   rpdq->render_pass_id = pass2->id;
 
   // Since pass3 is empty it should be removed. Then pass2 is empty too, and
@@ -12122,7 +12123,8 @@
   EXPECT_EQ(1u, frame.render_passes[0]->id);
   // The RenderPassDrawQuad should be removed from pass1.
   EXPECT_EQ(1u, pass1->quad_list.size());
-  EXPECT_EQ(DrawQuad::SOLID_COLOR, pass1->quad_list.ElementAt(0)->material);
+  EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+            pass1->quad_list.ElementAt(0)->material);
 }
 
 TEST_F(LayerTreeHostImplTest, DoNotRemoveEmptyRootRenderPass) {
@@ -12141,12 +12143,12 @@
   // pass3 is referenced by pass2.
   RenderPassDrawQuad* rpdq =
       pass2->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
-  rpdq->material = DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::RENDER_PASS;
   rpdq->render_pass_id = pass3->id;
 
   // pass2 is referenced by pass1.
   rpdq = pass1->CreateAndAppendDrawQuad<RenderPassDrawQuad>();
-  rpdq->material = DrawQuad::RENDER_PASS;
+  rpdq->material = viz::DrawQuad::RENDER_PASS;
   rpdq->render_pass_id = pass2->id;
 
   // Since pass3 is empty it should be removed. Then pass2 is empty too, and
diff --git a/cc/trees/layer_tree_host_unittest.cc b/cc/trees/layer_tree_host_unittest.cc
index f5a7619..469e860 100644
--- a/cc/trees/layer_tree_host_unittest.cc
+++ b/cc/trees/layer_tree_host_unittest.cc
@@ -27,7 +27,6 @@
 #include "cc/layers/video_layer.h"
 #include "cc/output/output_surface.h"
 #include "cc/output/swap_promise.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
 #include "cc/quads/tile_draw_quad.h"
 #include "cc/resources/ui_resource_manager.h"
@@ -62,6 +61,7 @@
 #include "components/viz/common/frame_sinks/begin_frame_args.h"
 #include "components/viz/common/quads/copy_output_request.h"
 #include "components/viz/common/quads/copy_output_result.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/test/begin_frame_args_test.h"
 #include "components/viz/test/test_layer_tree_frame_sink.h"
 #include "gpu/GLES2/gl2extchromium.h"
@@ -6337,7 +6337,7 @@
     RenderPass* root_pass = frame_data->render_passes.back().get();
     for (auto* draw_quad : root_pass->quad_list) {
       // Checkerboards mean an incomplete frame.
-      if (draw_quad->material != DrawQuad::TILED_CONTENT)
+      if (draw_quad->material != viz::DrawQuad::TILED_CONTENT)
         return 0.f;
       const TileDrawQuad* quad = TileDrawQuad::MaterialCast(draw_quad);
       float quad_scale =
@@ -7030,9 +7030,11 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.back()->material);
 
-    EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+              root_pass->quad_list.front()->material);
     const RenderPassDrawQuad* render_pass_quad =
         RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
     EXPECT_EQ(gfx::Rect(50, 50, 50, 50).ToString(),
@@ -7157,10 +7159,12 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.back()->material);
 
     // The surface is clipped to 10x20.
-    EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+              root_pass->quad_list.front()->material);
     const RenderPassDrawQuad* render_pass_quad =
         RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
     EXPECT_EQ(gfx::Rect(20, 10, 10, 20).ToString(),
@@ -7279,9 +7283,11 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.back()->material);
 
-    EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+              root_pass->quad_list.front()->material);
     const RenderPassDrawQuad* render_pass_quad =
         RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
     switch (host_impl->active_tree()->source_frame_number()) {
@@ -7408,10 +7414,12 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.back()->material);
 
     // The surface is 100x100
-    EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+              root_pass->quad_list.front()->material);
     const RenderPassDrawQuad* render_pass_quad =
         RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
@@ -7477,11 +7485,13 @@
     EXPECT_EQ(2u, root_pass->quad_list.size());
 
     // There's a solid color quad under everything.
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, root_pass->quad_list.back()->material);
+    EXPECT_EQ(viz::DrawQuad::SOLID_COLOR,
+              root_pass->quad_list.back()->material);
 
     // Mask layer tiles should not be skipped even if the mask layer is solid
     // color.
-    EXPECT_EQ(DrawQuad::RENDER_PASS, root_pass->quad_list.front()->material);
+    EXPECT_EQ(viz::DrawQuad::RENDER_PASS,
+              root_pass->quad_list.front()->material);
     const RenderPassDrawQuad* render_pass_quad =
         RenderPassDrawQuad::MaterialCast(root_pass->quad_list.front());
     EXPECT_EQ(gfx::Rect(0, 0, 100, 100).ToString(),
diff --git a/cc/trees/single_thread_proxy.cc b/cc/trees/single_thread_proxy.cc
index f608e7c8..61c5063b 100644
--- a/cc/trees/single_thread_proxy.cc
+++ b/cc/trees/single_thread_proxy.cc
@@ -11,7 +11,6 @@
 #include "cc/base/devtools_instrumentation.h"
 #include "cc/benchmarks/benchmark_instrumentation.h"
 #include "cc/output/layer_tree_frame_sink.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/resources/ui_resource_manager.h"
 #include "cc/scheduler/commit_earlyout_reason.h"
 #include "cc/scheduler/compositor_timing_history.h"
diff --git a/chrome/android/java/res/layout/snackbar.xml b/chrome/android/java/res/layout/snackbar.xml
index d466784..b13bb93 100644
--- a/chrome/android/java/res/layout/snackbar.xml
+++ b/chrome/android/java/res/layout/snackbar.xml
@@ -4,46 +4,57 @@
      found in the LICENSE file. -->
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/snackbar"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="bottom|start"
-    android:minHeight="@dimen/snackbar_min_height"
-    android:orientation="horizontal" >
+    android:orientation="vertical" >
 
-    <ImageView android:id="@+id/snackbar_profile_image"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:layout_gravity="center_vertical"
-        android:layout_marginStart="12dp"
-        android:layout_marginEnd="-12dp"
-        android:scaleType="fitCenter"
-        android:visibility="visible"
-        android:contentDescription="@null"/>
+    <View
+        android:id="@+id/snackbar_shadow"
+        android:layout_width="match_parent"
+        android:layout_height="@dimen/snackbar_shadow_height"
+        android:background="@drawable/infobar_shadow_top"
+        android:visibility="gone" />
 
-    <org.chromium.chrome.browser.snackbar.TemplatePreservingTextView
-        android:id="@+id/snackbar_message"
-        android:layout_width="0dp"
+    <LinearLayout
+        android:id="@+id/snackbar"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:layout_gravity="start|center_vertical"
-        android:layout_marginStart="24dp"
-        android:layout_marginTop="14dp"
-        android:layout_marginBottom="14dp"
-        android:layout_weight="1"
-        android:textAlignment="viewStart"
-        android:textColor="@android:color/white"
-        android:textSize="14sp" />
+        android:minHeight="@dimen/snackbar_min_height"
+        android:orientation="horizontal" >
 
-    <Button
-        android:id="@+id/snackbar_button"
-        android:layout_width="wrap_content"
-        android:layout_height="@dimen/snackbar_min_height"
-        android:layout_gravity="center_vertical"
-        android:paddingEnd="24dp"
-        android:paddingStart="24dp"
-        android:textAllCaps="true"
-        android:textColor="@color/snackbar_button_color"
-        android:textSize="14sp"
-        style="@style/ButtonCompatBorderless" />
+        <ImageView android:id="@+id/snackbar_profile_image"
+            android:layout_width="24dp"
+            android:layout_height="24dp"
+            android:layout_gravity="center_vertical"
+            android:layout_marginStart="12dp"
+            android:layout_marginEnd="-12dp"
+            android:scaleType="fitCenter"
+            android:visibility="visible"
+            android:contentDescription="@null"/>
 
+        <org.chromium.chrome.browser.snackbar.TemplatePreservingTextView
+            android:id="@+id/snackbar_message"
+            android:layout_width="0dp"
+            android:layout_height="wrap_content"
+            android:layout_gravity="start|center_vertical"
+            android:layout_marginStart="24dp"
+            android:layout_marginTop="14dp"
+            android:layout_marginBottom="14dp"
+            android:layout_weight="1"
+            android:textAlignment="viewStart"
+            android:textAppearance="@style/WhiteBody" />
+
+        <Button
+            android:id="@+id/snackbar_button"
+            android:layout_width="wrap_content"
+            android:layout_height="@dimen/snackbar_min_height"
+            android:layout_gravity="center_vertical"
+            android:paddingEnd="24dp"
+            android:paddingStart="24dp"
+            android:textAllCaps="true"
+            android:textColor="@color/snackbar_button_color"
+            android:textSize="@dimen/text_size_medium"
+            style="@style/ButtonCompatBorderless" />
+    </LinearLayout>
 </LinearLayout>
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index b398d428..6293669 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -376,6 +376,7 @@
     <dimen name="snackbar_min_height">48dp</dimen>
     <dimen name="snackbar_width_tablet">450dp</dimen>
     <dimen name="snackbar_margin_tablet">24dp</dimen>
+    <dimen name="snackbar_shadow_height">8dp</dimen>
 
     <!-- Bookmarks dimensions -->
     <dimen name="bookmark_item_popup_width">140dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
index 7913dab..afcd671 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeSwitches.java
@@ -186,6 +186,9 @@
     /** Switch for enabling "button only" swipe logic for Chrome Home. */
     public static final String CHROME_HOME_SWIPE_LOGIC_BUTTON_ONLY = "button-only";
 
+    /** Switch for enabling downloads as a foreground service for all versions of Android. */
+    public static final String ENABLE_DOWNLOADS_FOREGROUND = "enable-downloads-foreground";
+
     // Prevent instantiation.
     private ChromeSwitches() {}
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
index f47e263..a709197 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/appmenu/AppMenu.java
@@ -500,7 +500,7 @@
         int availableScreenSpace = Math.max(
                 anchorViewY, appDimensions.height() - anchorViewY - anchorViewImpactHeight);
 
-        availableScreenSpace -= padding.bottom + footerHeight;
+        availableScreenSpace -= (padding.bottom + footerHeight + headerHeight);
         if (mIsByPermanentButton) availableScreenSpace -= padding.top;
 
         int numCanFit = availableScreenSpace / (mItemRowHeight + mItemDividerHeight);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
index a50eff9..4b8f4c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TabContentManager.java
@@ -235,19 +235,6 @@
         }
     }
 
-    /**
-     * Send a request to thumbnail store to read and decompress the thumbnail for the given tab id.
-     * @param tabId The tab id for which the thumbnail should be requested.
-     * @param callback The callback to use when the thumbnail bitmap is decompressed and sent back.
-     */
-    public void getThumbnailForId(int tabId, DecompressThumbnailCallback callback) {
-        if (mNativeTabContentManager == 0) return;
-        if (mDecompressRequests.get(tabId) != null) return;
-
-        mDecompressRequests.put(tabId, callback);
-        nativeGetDecompressedThumbnail(mNativeTabContentManager, tabId);
-    }
-
     @CalledByNative
     private void notifyDecompressBitmapFinished(int tabId, Bitmap bitmap) {
         DecompressThumbnailCallback callback = mDecompressRequests.get(tabId);
@@ -327,6 +314,5 @@
     private native void nativeUpdateVisibleIds(
             long nativeTabContentManager, int[] priority, int primaryTabId);
     private native void nativeRemoveTabThumbnail(long nativeTabContentManager, int tabId);
-    private native void nativeGetDecompressedThumbnail(long nativeTabContentManager, int tabId);
     private static native void nativeDestroy(long nativeTabContentManager);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
index 7fde20c..0a2e271 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -19,6 +19,7 @@
 import android.util.Pair;
 
 import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.base.CommandLine;
 import org.chromium.base.ContextUtils;
 import org.chromium.base.Log;
 import org.chromium.base.ObserverList;
@@ -28,6 +29,7 @@
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeSwitches;
 import org.chromium.chrome.browser.download.ui.BackendProvider;
 import org.chromium.chrome.browser.download.ui.DownloadHistoryAdapter;
 import org.chromium.chrome.browser.externalnav.ExternalNavigationDelegateImpl;
@@ -190,8 +192,12 @@
         ThreadUtils.assertOnUiThread();
         Context appContext = ContextUtils.getApplicationContext();
         if (sDownloadManagerService == null) {
-            sDownloadManagerService = new DownloadManagerService(appContext,
-                    new SystemDownloadNotifier(appContext), new Handler(), UPDATE_DELAY_MILLIS);
+            DownloadNotifier downloadNotifier =
+                    CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_DOWNLOADS_FOREGROUND)
+                    ? new SystemDownloadNotifier2(appContext)
+                    : new SystemDownloadNotifier(appContext);
+            sDownloadManagerService = new DownloadManagerService(
+                    appContext, downloadNotifier, new Handler(), UPDATE_DELAY_MILLIS);
         }
         return sDownloadManagerService;
     }
@@ -328,13 +334,11 @@
                 (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
         NetworkInfo info = cm.getActiveNetworkInfo();
         if (info == null || !info.isConnected()) return;
-        if (progress.mCanDownloadWhileMetered && !isActiveNetworkMetered(mContext)) {
+        if (progress.mCanDownloadWhileMetered || !isActiveNetworkMetered(mContext)) {
             // Normally the download will automatically resume when network is reconnected.
             // However, if there are multiple network connections and the interruption is caused
             // by switching between active networks, onConnectionTypeChanged() will not get called.
             // As a result, we should resume immediately.
-            // TODO(qinmin): Handle the case if the interruption is caused by switching between
-            // 2 metered networks or 2 non-metered networks on device with multiple antennas.
             scheduleDownloadResumption(item);
         }
     }
@@ -1369,10 +1373,17 @@
      */
     @Override
     public void broadcastDownloadAction(DownloadItem downloadItem, String action) {
-        Intent intent = DownloadNotificationService.buildActionIntent(mContext, action,
-                LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
-                downloadItem.getDownloadInfo().isOffTheRecord());
-        mContext.sendBroadcast(intent);
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_DOWNLOADS_FOREGROUND)) {
+            Intent intent = DownloadNotificationFactory.buildActionIntent(mContext, action,
+                    LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
+                    downloadItem.getDownloadInfo().isOffTheRecord());
+            mContext.startService(intent);
+        } else {
+            Intent intent = DownloadNotificationService.buildActionIntent(mContext, action,
+                    LegacyHelpers.buildLegacyContentId(false, downloadItem.getId()),
+                    downloadItem.getDownloadInfo().isOffTheRecord());
+            mContext.sendBroadcast(intent);
+        }
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
index 46771ed3..7f626b0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadNotificationService2.java
@@ -56,8 +56,6 @@
     public static final String ACTION_DOWNLOAD_OPEN =
             "org.chromium.chrome.browser.download.DOWNLOAD_OPEN";
 
-    public static final String NOTIFICATION_NAMESPACE = "DownloadNotificationService";
-
     public static final String EXTRA_NOTIFICATION_BUNDLE_ICON_ID =
             "Chrome.NotificationBundleIconIdExtra";
     /** Notification Id starting value, to avoid conflicts from IDs used in prior versions. */
@@ -236,7 +234,8 @@
     }
 
     public void cancelNotification(int notificationId) {
-        mNotificationManager.cancel(NOTIFICATION_NAMESPACE, notificationId);
+        // TODO(b/65052774): Add back NOTIFICATION_NAMESPACE when able to.
+        mNotificationManager.cancel(notificationId);
     }
 
     /**
@@ -450,7 +449,8 @@
 
     @VisibleForTesting
     void updateNotification(int id, Notification notification) {
-        mNotificationManager.notify(NOTIFICATION_NAMESPACE, id, notification);
+        // TODO(b/65052774): Add back NOTIFICATION_NAMESPACE when able to.
+        mNotificationManager.notify(id, notification);
     }
 
     private void updateNotification(int notificationId, Notification notification, ContentId id,
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
index b584fb2..c0e2896 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java
@@ -12,10 +12,12 @@
 import com.google.android.gms.gcm.OneoffTask;
 import com.google.android.gms.gcm.Task;
 
+import org.chromium.base.CommandLine;
 import org.chromium.base.Log;
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.SuppressFBWarnings;
 import org.chromium.chrome.browser.ChromeBackgroundService;
+import org.chromium.chrome.browser.ChromeSwitches;
 
 /**
  * Class for scheduing download resumption tasks.
@@ -43,7 +45,7 @@
 
     /**
      * For tests only: sets the DownloadResumptionScheduler.
-     * @param service An instance of DownloadResumptionScheduler.
+     * @param scheduler An instance of DownloadResumptionScheduler.
      */
     @VisibleForTesting
     public static void setDownloadResumptionScheduler(DownloadResumptionScheduler scheduler) {
@@ -85,9 +87,15 @@
      * Start browser process and resumes all interrupted downloads.
      */
     public void handleDownloadResumption() {
-        // Fire an intent to the DownloadNotificationService so that it will handle download
-        // resumption.
-        Intent intent = new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL);
-        DownloadNotificationService.startDownloadNotificationService(mContext, intent);
+        if (CommandLine.getInstance().hasSwitch(ChromeSwitches.ENABLE_DOWNLOADS_FOREGROUND)) {
+            DownloadNotificationService2 downloadNotificationService2 =
+                    DownloadNotificationService2.getInstance();
+            downloadNotificationService2.resumeAllPendingDownloads();
+        } else {
+            // Fire an intent to the DownloadNotificationService so that it will handle download
+            // resumption.
+            Intent intent = new Intent(DownloadNotificationService.ACTION_DOWNLOAD_RESUME_ALL);
+            DownloadNotificationService.startDownloadNotificationService(mContext, intent);
+        }
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java
deleted file mode 100644
index 3537e3d..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java
+++ /dev/null
@@ -1,91 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.download;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-
-import com.google.android.gms.gcm.GcmNetworkManager;
-import com.google.android.gms.gcm.OneoffTask;
-import com.google.android.gms.gcm.Task;
-
-import org.chromium.base.Log;
-import org.chromium.base.VisibleForTesting;
-import org.chromium.base.annotations.SuppressFBWarnings;
-import org.chromium.chrome.browser.ChromeBackgroundService;
-
-/**
- * Class for scheduling download resumption tasks.
- */
-public class DownloadResumptionScheduler2 {
-    public static final String TASK_TAG = "DownloadResumption";
-    private static final String TAG = "DownloadScheduler";
-    private static final int ONE_DAY_IN_SECONDS = 24 * 60 * 60;
-    private final Context mContext;
-    private final DownloadNotificationService2 mDownloadNotificationService;
-    @SuppressLint("StaticFieldLeak")
-    private static DownloadResumptionScheduler2 sDownloadResumptionScheduler;
-
-    @SuppressFBWarnings("LI_LAZY_INIT")
-    public static DownloadResumptionScheduler2 getDownloadResumptionScheduler(Context context) {
-        assert context == context.getApplicationContext();
-        if (sDownloadResumptionScheduler == null) {
-            sDownloadResumptionScheduler = new DownloadResumptionScheduler2(context);
-        }
-        return sDownloadResumptionScheduler;
-    }
-
-    protected DownloadResumptionScheduler2(Context context) {
-        mContext = context;
-        mDownloadNotificationService = DownloadNotificationService2.getInstance();
-    }
-
-    /**
-     * For tests only: sets the DownloadResumptionScheduler.
-     * @param scheduler An instance of DownloadResumptionScheduler.
-     */
-    @VisibleForTesting
-    public static void setDownloadResumptionScheduler(DownloadResumptionScheduler2 scheduler) {
-        sDownloadResumptionScheduler = scheduler;
-    }
-
-    /**
-     * Schedules a future task to start download resumption.
-     * @param allowMeteredConnection Whether download resumption can start if connection is metered.
-     */
-    public void schedule(boolean allowMeteredConnection) {
-        GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(mContext);
-        int networkType = allowMeteredConnection ? Task.NETWORK_STATE_CONNECTED
-                                                 : Task.NETWORK_STATE_UNMETERED;
-        OneoffTask task = new OneoffTask.Builder()
-                                  .setService(ChromeBackgroundService.class)
-                                  .setExecutionWindow(0, ONE_DAY_IN_SECONDS)
-                                  .setTag(TASK_TAG)
-                                  .setUpdateCurrent(true)
-                                  .setRequiredNetwork(networkType)
-                                  .setRequiresCharging(false)
-                                  .build();
-        try {
-            gcmNetworkManager.schedule(task);
-        } catch (IllegalArgumentException e) {
-            Log.e(TAG, "unable to schedule resumption task.", e);
-        }
-    }
-
-    /**
-     * Cancels a download resumption task if it is scheduled.
-     */
-    public void cancelTask() {
-        GcmNetworkManager gcmNetworkManager = GcmNetworkManager.getInstance(mContext);
-        gcmNetworkManager.cancelTask(TASK_TAG, ChromeBackgroundService.class);
-    }
-
-    /**
-     * Start browser process and resumes all interrupted downloads.
-     */
-    public void handleDownloadResumption() {
-        mDownloadNotificationService.resumeAllPendingDownloads();
-    }
-}
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
index fb96ac6..ffb34c95 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/SystemDownloadNotifier.java
@@ -39,6 +39,7 @@
     private static final int DOWNLOAD_NOTIFICATION_TYPE_REMOVE_NOTIFICATION = 7;
 
     private final Context mApplicationContext;
+
     @Nullable
     private DownloadNotificationService mBoundService;
     private Set<String> mActiveDownloads = new HashSet<String>();
@@ -222,7 +223,6 @@
     @Override
     public void resumePendingDownloads() {
         if (!DownloadNotificationService.isTrackingResumableDownloads(mApplicationContext)) return;
-
         updateDownloadNotification(
                 new PendingNotificationInfo(DOWNLOAD_NOTIFICATION_TYPE_RESUME_ALL, null), true);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
index 38446f5..5a0d2dc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarView.java
@@ -28,6 +28,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
@@ -39,10 +40,12 @@
     private static final int MAX_LINES = 5;
 
     private final Activity mActivity;
-    private final ViewGroup mView;
+    private final ViewGroup mContainerView;
+    private final ViewGroup mSnackbarView;
     private final TemplatePreservingTextView mMessageView;
     private final TextView mActionButtonView;
     private final ImageView mProfileImageView;
+    private final View mShadowView;
     private final int mAnimationDuration;
     private final boolean mIsTablet;
     private ViewGroup mOriginalParent;
@@ -87,27 +90,31 @@
 
         mRootContentView = activity.findViewById(android.R.id.content);
         mParent = mOriginalParent;
-        mView = (ViewGroup) LayoutInflater.from(activity).inflate(
+        mContainerView = (ViewGroup) LayoutInflater.from(activity).inflate(
                 R.layout.snackbar, mParent, false);
-        mAnimationDuration = mView.getResources()
-                .getInteger(android.R.integer.config_mediumAnimTime);
-        mMessageView = (TemplatePreservingTextView) mView.findViewById(R.id.snackbar_message);
-        mActionButtonView = (TextView) mView.findViewById(R.id.snackbar_button);
+        mSnackbarView = mContainerView.findViewById(R.id.snackbar);
+        mAnimationDuration =
+                mContainerView.getResources().getInteger(android.R.integer.config_mediumAnimTime);
+        mMessageView =
+                (TemplatePreservingTextView) mContainerView.findViewById(R.id.snackbar_message);
+        mActionButtonView = (TextView) mContainerView.findViewById(R.id.snackbar_button);
         mActionButtonView.setOnClickListener(listener);
-        mProfileImageView = (ImageView) mView.findViewById(R.id.snackbar_profile_image);
+        mProfileImageView = (ImageView) mContainerView.findViewById(R.id.snackbar_profile_image);
+        mShadowView = mContainerView.findViewById(R.id.snackbar_shadow);
 
         updateInternal(snackbar, false);
     }
 
     void show() {
         addToParent();
-        mView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
+        mContainerView.addOnLayoutChangeListener(new OnLayoutChangeListener() {
             @Override
             public void onLayoutChange(View v, int left, int top, int right, int bottom,
                     int oldLeft, int oldTop, int oldRight, int oldBottom) {
-                mView.removeOnLayoutChangeListener(this);
-                mView.setTranslationY(mView.getHeight() + getLayoutParams().bottomMargin);
-                Animator animator = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y, 0);
+                mContainerView.removeOnLayoutChangeListener(this);
+                mContainerView.setTranslationY(
+                        mContainerView.getHeight() + getLayoutParams().bottomMargin);
+                Animator animator = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y, 0);
                 animator.setInterpolator(new DecelerateInterpolator());
                 animator.setDuration(mAnimationDuration);
                 startAnimatorOnSurfaceView(animator);
@@ -124,13 +131,13 @@
             @Override
             public void onAnimationEnd(Animator animation) {
                 mRootContentView.removeOnLayoutChangeListener(mLayoutListener);
-                mParent.removeView(mView);
+                mParent.removeView(mContainerView);
             }
         });
-        Animator moveDown = ObjectAnimator.ofFloat(mView, View.TRANSLATION_Y,
-                mView.getHeight() + getLayoutParams().bottomMargin);
+        Animator moveDown = ObjectAnimator.ofFloat(mContainerView, View.TRANSLATION_Y,
+                mContainerView.getHeight() + getLayoutParams().bottomMargin);
         moveDown.setInterpolator(new DecelerateInterpolator());
-        Animator fadeOut = ObjectAnimator.ofFloat(mView, View.ALPHA, 0f);
+        Animator fadeOut = ObjectAnimator.ofFloat(mContainerView, View.ALPHA, 0f);
         fadeOut.setInterpolator(BakedBezierInterpolator.FADE_OUT_CURVE);
 
         animatorSet.playTogether(fadeOut, moveDown);
@@ -168,7 +175,7 @@
 
             if (prevBottomMargin != lp.bottomMargin || prevWidth != lp.width
                     || prevGravity != lp.gravity) {
-                mView.setLayoutParams(lp);
+                mContainerView.setLayoutParams(lp);
             }
         }
     }
@@ -180,17 +187,17 @@
         mRootContentView.removeOnLayoutChangeListener(mLayoutListener);
         mParent = overridingParent == null ? mOriginalParent : overridingParent;
         if (isShowing()) {
-            ((ViewGroup) mView.getParent()).removeView(mView);
+            ((ViewGroup) mContainerView.getParent()).removeView(mContainerView);
         }
         addToParent();
     }
 
     boolean isShowing() {
-        return mView.isShown();
+        return mContainerView.isShown();
     }
 
     void bringToFront() {
-        mView.bringToFront();
+        mContainerView.bringToFront();
     }
 
     /**
@@ -199,7 +206,7 @@
      */
     void announceforAccessibility() {
         mMessageView.announceForAccessibility(mMessageView.getContentDescription() + " "
-                + mView.getResources().getString(R.string.bottom_bar_screen_position));
+                + mContainerView.getResources().getString(R.string.bottom_bar_screen_position));
     }
 
     /**
@@ -213,7 +220,7 @@
     }
 
     private void addToParent() {
-        mParent.addView(mView);
+        mParent.addView(mContainerView);
 
         // Why setting listener on parent? It turns out that if we force a relayout in the layout
         // change listener of the view itself, the force layout flag will be reset to 0 when
@@ -232,17 +239,20 @@
 
         int backgroundColor = snackbar.getBackgroundColor();
         if (backgroundColor == 0) {
-            backgroundColor = ApiCompatibilityUtils.getColor(mView.getResources(),
-                    R.color.snackbar_background_color);
+            backgroundColor = ApiCompatibilityUtils.getColor(mContainerView.getResources(),
+                    FeatureUtilities.isChromeHomeModernEnabled()
+                            ? R.color.modern_primary_color
+                            : R.color.snackbar_background_color);
         }
 
         if (mIsTablet) {
             // On tablet, snackbars have rounded corners.
-            mView.setBackgroundResource(R.drawable.snackbar_background_tablet);
-            GradientDrawable backgroundDrawable = (GradientDrawable) mView.getBackground().mutate();
+            mSnackbarView.setBackgroundResource(R.drawable.snackbar_background_tablet);
+            GradientDrawable backgroundDrawable =
+                    (GradientDrawable) mSnackbarView.getBackground().mutate();
             backgroundDrawable.setColor(backgroundColor);
         } else {
-            mView.setBackgroundColor(backgroundColor);
+            mSnackbarView.setBackgroundColor(backgroundColor);
         }
 
         if (actionText != null) {
@@ -258,11 +268,18 @@
         } else {
             mProfileImageView.setVisibility(View.GONE);
         }
+
+        if (FeatureUtilities.isChromeHomeModernEnabled()) {
+            ApiCompatibilityUtils.setTextAppearance(mMessageView, R.style.BlackBodyDefault);
+            mActionButtonView.setTextColor(ApiCompatibilityUtils.getColor(
+                    mContainerView.getResources(), R.color.blue_when_enabled));
+            mShadowView.setVisibility(View.VISIBLE);
+        }
         return true;
     }
 
     /**
-     * @return The parent {@link ViewGroup} that {@link #mView} will be added to.
+     * @return The parent {@link ViewGroup} that {@link #mContainerView} will be added to.
      */
     private ViewGroup findParentView(Activity activity) {
         if (activity instanceof ChromeActivity) {
@@ -286,7 +303,7 @@
     }
 
     private FrameLayout.LayoutParams getLayoutParams() {
-        return (FrameLayout.LayoutParams) mView.getLayoutParams();
+        return (FrameLayout.LayoutParams) mContainerView.getLayoutParams();
     }
 
     private void setViewText(TextView view, CharSequence text, boolean animate) {
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 4ee5defa..2c8c9c3e 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -339,7 +339,6 @@
   "java/src/org/chromium/chrome/browser/download/DownloadNotifier.java",
   "java/src/org/chromium/chrome/browser/download/DownloadPage.java",
   "java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler.java",
-  "java/src/org/chromium/chrome/browser/download/DownloadResumptionScheduler2.java",
   "java/src/org/chromium/chrome/browser/download/DownloadServiceDelegate.java",
   "java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceEntry.java",
   "java/src/org/chromium/chrome/browser/download/DownloadSharedPreferenceHelper.java",
diff --git a/chrome/browser/OWNERS b/chrome/browser/OWNERS
index 94a49cb..1813d76b 100644
--- a/chrome/browser/OWNERS
+++ b/chrome/browser/OWNERS
@@ -58,6 +58,8 @@
 per-file chrome_security_exploit_browsertest.cc=alexmos@chromium.org
 per-file chrome_security_exploit_browsertest.cc=file://content/OWNERS
 
+per-file chrome_service_worker_browsertest.cc=file://content/browser/service_worker/OWNERS
+
 per-file chrome_site_per_process_browsertest.cc=alexmos@chromium.org
 per-file chrome_site_per_process_browsertest.cc=file://content/OWNERS
 
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index c31f4ed..789b9b73 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -306,17 +306,6 @@
   NativeRemoveTabThumbnail(tab_id);
 }
 
-void TabContentManager::GetDecompressedThumbnail(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    jint tab_id) {
-  base::Callback<void(bool, SkBitmap)> decompress_done_callback =
-      base::Bind(&TabContentManager::OnFinishDecompressThumbnail,
-                 weak_factory_.GetWeakPtr(), reinterpret_cast<int>(tab_id));
-  thumbnail_cache_->DecompressThumbnailFromFile(reinterpret_cast<int>(tab_id),
-                                                decompress_done_callback);
-}
-
 void TabContentManager::OnUIResourcesWereEvicted() {
   thumbnail_cache_->OnUIResourcesWereEvicted();
 }
diff --git a/chrome/browser/android/compositor/tab_content_manager.h b/chrome/browser/android/compositor/tab_content_manager.h
index 25ef67f4..0dc08d2 100644
--- a/chrome/browser/android/compositor/tab_content_manager.h
+++ b/chrome/browser/android/compositor/tab_content_manager.h
@@ -97,9 +97,6 @@
   void RemoveTabThumbnail(JNIEnv* env,
                           const base::android::JavaParamRef<jobject>& obj,
                           jint tab_id);
-  void GetDecompressedThumbnail(JNIEnv* env,
-                                const base::android::JavaParamRef<jobject>& obj,
-                                jint tab_id);
   void OnUIResourcesWereEvicted();
 
   // ThumbnailCacheObserver implementation;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index e8361e5..91a5468 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -1382,8 +1382,6 @@
     "printing/synced_printers_manager_factory.h",
     "printing/usb_printer_detector.cc",
     "printing/usb_printer_detector.h",
-    "printing/usb_printer_detector_factory.cc",
-    "printing/usb_printer_detector_factory.h",
     "printing/usb_printer_util.cc",
     "printing/usb_printer_util.h",
     "printing/zeroconf_printer_detector.cc",
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 3ef7c4b..2fb5353 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -480,12 +480,6 @@
   login_screen_started_ = true;
 }
 
-void WizardController::ShowUpdateScreen() {
-  VLOG(1) << "Showing update screen.";
-  UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_OOBE_UPDATE);
-  SetCurrentScreen(GetScreen(OobeScreen::SCREEN_OOBE_UPDATE));
-}
-
 void WizardController::ShowUserImageScreen() {
   const user_manager::UserManager* user_manager =
       user_manager::UserManager::Get();
@@ -706,12 +700,6 @@
   }
 }
 
-void WizardController::OnNetworkOffline() {
-  // TODO(dpolukhin): if(is_out_of_box_) we cannot work offline and
-  // should report some error message here and stay on the same screen.
-  ShowLoginScreen(LoginScreenContext());
-}
-
 void WizardController::OnConnectionFailed() {
   // TODO(dpolukhin): show error message after login screen is displayed.
   ShowLoginScreen(LoginScreenContext());
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h
index d6e982e3..9b88c10a6 100644
--- a/chrome/browser/chromeos/login/wizard_controller.h
+++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -132,7 +132,6 @@
  private:
   // Show specific screen.
   void ShowNetworkScreen();
-  void ShowUpdateScreen();
   void ShowUserImageScreen();
   void ShowEulaScreen();
   void ShowEnrollmentScreen();
@@ -160,7 +159,6 @@
   // Exit handlers:
   void OnHIDDetectionCompleted();
   void OnNetworkConnected();
-  void OnNetworkOffline();
   void OnConnectionFailed();
   void OnUpdateCompleted();
   void OnEulaAccepted();
@@ -169,7 +167,6 @@
   void OnUserImageSelected();
   void OnUserImageSkipped();
   void OnEnrollmentDone();
-  void OnAutoEnrollmentDone();
   void OnDeviceModificationCanceled();
   void OnKioskAutolaunchCanceled();
   void OnKioskAutolaunchConfirmed();
@@ -193,12 +190,6 @@
   // Callback function after setting MetricsReporting.
   void OnChangedMetricsReportingState(bool enabled);
 
-  // Loads brand code on I/O enabled thread and stores to Local State.
-  void LoadBrandCodeFromFile();
-
-  // Called after all post-EULA blocking tasks have been completed.
-  void OnEulaBlockingTasksDone();
-
   // Shows update screen and starts update process.
   void InitiateOOBEUpdate();
   void StartOOBEUpdate();
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.cc b/chrome/browser/chromeos/printing/cups_printers_manager.cc
index 74505595..777745e5 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.cc
@@ -20,7 +20,6 @@
 #include "chrome/browser/chromeos/printing/synced_printers_manager.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
 #include "chrome/browser/chromeos/printing/usb_printer_detector.h"
-#include "chrome/browser/chromeos/printing/usb_printer_detector_factory.h"
 #include "chrome/browser/chromeos/printing/zeroconf_printer_detector.h"
 #include "chrome/browser/profiles/profile.h"
 
@@ -82,13 +81,13 @@
   };
 
   CupsPrintersManagerImpl(SyncedPrintersManager* synced_printers_manager,
-                          PrinterDetector* usb_detector,
+                          std::unique_ptr<PrinterDetector> usb_detector,
                           std::unique_ptr<PrinterDetector> zeroconf_detector,
                           scoped_refptr<PpdProvider> ppd_provider,
                           PrinterEventTracker* event_tracker)
       : synced_printers_manager_(synced_printers_manager),
         synced_printers_manager_observer_(this),
-        usb_detector_(usb_detector),
+        usb_detector_(std::move(usb_detector)),
         zeroconf_detector_(std::move(zeroconf_detector)),
         ppd_provider_(std::move(ppd_provider)),
         event_tracker_(event_tracker),
@@ -104,7 +103,7 @@
     // these instantiations must come after everything else is initialized.
     usb_detector_observer_proxy_ =
         base::MakeUnique<PrinterDetectorObserverProxy>(this, kUsbDetector,
-                                                       usb_detector_);
+                                                       usb_detector_.get());
     zeroconf_detector_observer_proxy_ =
         base::MakeUnique<PrinterDetectorObserverProxy>(
             this, kZeroconfDetector, zeroconf_detector_.get());
@@ -442,8 +441,7 @@
   ScopedObserver<SyncedPrintersManager, SyncedPrintersManager::Observer>
       synced_printers_manager_observer_;
 
-  // Not owned.
-  PrinterDetector* usb_detector_;
+  std::unique_ptr<PrinterDetector> usb_detector_;
   std::unique_ptr<PrinterDetectorObserverProxy> usb_detector_observer_proxy_;
 
   std::unique_ptr<PrinterDetector> zeroconf_detector_;
@@ -495,21 +493,21 @@
   return base::MakeUnique<CupsPrintersManagerImpl>(
       SyncedPrintersManagerFactory::GetInstance()->GetForBrowserContext(
           profile),
-      UsbPrinterDetectorFactory::GetInstance()->Get(profile),
-      ZeroconfPrinterDetector::Create(profile), CreatePpdProvider(profile),
+      UsbPrinterDetector::Create(), ZeroconfPrinterDetector::Create(profile),
+      CreatePpdProvider(profile),
       PrinterEventTrackerFactory::GetInstance()->GetForBrowserContext(profile));
 }
 
 // static
 std::unique_ptr<CupsPrintersManager> CupsPrintersManager::Create(
     SyncedPrintersManager* synced_printers_manager,
-    PrinterDetector* usb_detector,
+    std::unique_ptr<PrinterDetector> usb_detector,
     std::unique_ptr<PrinterDetector> zeroconf_detector,
     scoped_refptr<PpdProvider> ppd_provider,
     PrinterEventTracker* event_tracker) {
   return base::MakeUnique<CupsPrintersManagerImpl>(
-      synced_printers_manager, usb_detector, std::move(zeroconf_detector),
-      std::move(ppd_provider), event_tracker);
+      synced_printers_manager, std::move(usb_detector),
+      std::move(zeroconf_detector), std::move(ppd_provider), event_tracker);
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager.h b/chrome/browser/chromeos/printing/cups_printers_manager.h
index 7d35a98..dfceb71 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager.h
+++ b/chrome/browser/chromeos/printing/cups_printers_manager.h
@@ -50,7 +50,7 @@
   // is not taken of any of the raw-pointer arguments.
   static std::unique_ptr<CupsPrintersManager> Create(
       SyncedPrintersManager* synced_printers_manager,
-      PrinterDetector* usb_printer_detector,
+      std::unique_ptr<PrinterDetector> usb_printer_detector,
       std::unique_ptr<PrinterDetector> zeroconf_printer_detector,
       scoped_refptr<PpdProvider> ppd_provider,
       PrinterEventTracker* event_tracker);
diff --git a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
index 6a6ae9757..e7c68f9 100644
--- a/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
+++ b/chrome/browser/chromeos/printing/cups_printers_manager_unittest.cc
@@ -251,13 +251,15 @@
   CupsPrintersManagerTest()
       : observed_printers_(CupsPrintersManager::kNumPrinterClasses),
         ppd_provider_(new FakePpdProvider) {
-    // Zeroconf detector ownership is taken by the manager, so we have
-    // to keep a raw pointer to it.
+    // Zeroconf and usb detector ownerships are taken by the manager, so we have
+    // to keep raw pointers to them.
     auto zeroconf_detector = base::MakeUnique<FakePrinterDetector>();
     zeroconf_detector_ = zeroconf_detector.get();
+    auto usb_detector = base::MakeUnique<FakePrinterDetector>();
+    usb_detector_ = usb_detector.get();
     manager_ = CupsPrintersManager::Create(
-        &synced_printers_manager_, &usb_detector_, std::move(zeroconf_detector),
-        ppd_provider_, &event_tracker_);
+        &synced_printers_manager_, std::move(usb_detector),
+        std::move(zeroconf_detector), ppd_provider_, &event_tracker_);
     manager_->AddObserver(this);
   }
 
@@ -286,7 +288,7 @@
 
   // Backend fakes driving the CupsPrintersManager.
   FakeSyncedPrintersManager synced_printers_manager_;
-  FakePrinterDetector usb_detector_;
+  FakePrinterDetector* usb_detector_;
   FakePrinterDetector* zeroconf_detector_;
   scoped_refptr<FakePpdProvider> ppd_provider_;
 
@@ -340,8 +342,8 @@
 // surfaced appropriately.  One printer should be "automatic" because it has
 // a findable Ppd, the other should be "discovered".
 TEST_F(CupsPrintersManagerTest, GetUsbPrinters) {
-  usb_detector_.AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
-                               MakeAutomaticPrinter("AutomaticPrinter")});
+  usb_detector_->AddDetections({MakeDiscoveredPrinter("DiscoveredPrinter"),
+                                MakeAutomaticPrinter("AutomaticPrinter")});
   scoped_task_environment_.RunUntilIdle();
   ExpectPrintersInClassAre(CupsPrintersManager::kDiscovered,
                            {"DiscoveredPrinter"});
@@ -402,7 +404,7 @@
   // Enterprise which is not relevant to this test.
   Printer existing_configured("Configured");
   synced_printers_manager_.AddConfiguredPrinters({existing_configured});
-  usb_detector_.AddDetections({MakeDiscoveredPrinter("Discovered")});
+  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
   zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
   scoped_task_environment_.RunUntilIdle();
 
@@ -457,7 +459,7 @@
 TEST_F(CupsPrintersManagerTest, GetPrinter) {
   synced_printers_manager_.AddConfiguredPrinters({Printer("Configured")});
   synced_printers_manager_.AddEnterprisePrinters({Printer("Enterprise")});
-  usb_detector_.AddDetections({MakeDiscoveredPrinter("Discovered")});
+  usb_detector_->AddDetections({MakeDiscoveredPrinter("Discovered")});
   zeroconf_detector_->AddDetections({MakeAutomaticPrinter("Automatic")});
   scoped_task_environment_.RunUntilIdle();
 
diff --git a/chrome/browser/chromeos/printing/usb_printer_detector.cc b/chrome/browser/chromeos/printing/usb_printer_detector.cc
index a80b3f4..a27c305 100644
--- a/chrome/browser/chromeos/printing/usb_printer_detector.cc
+++ b/chrome/browser/chromeos/printing/usb_printer_detector.cc
@@ -53,7 +53,7 @@
 class UsbPrinterDetectorImpl : public UsbPrinterDetector,
                                public device::UsbService::Observer {
  public:
-  explicit UsbPrinterDetectorImpl(Profile* profile)
+  UsbPrinterDetectorImpl()
       : usb_observer_(this),
         observer_list_(
             new base::ObserverListThreadSafe<UsbPrinterDetector::Observer>),
@@ -180,9 +180,8 @@
 }  // namespace
 
 // static
-std::unique_ptr<UsbPrinterDetector> UsbPrinterDetector::Create(
-    Profile* profile) {
-  return base::MakeUnique<UsbPrinterDetectorImpl>(profile);
+std::unique_ptr<UsbPrinterDetector> UsbPrinterDetector::Create() {
+  return base::MakeUnique<UsbPrinterDetectorImpl>();
 }
 
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/usb_printer_detector.h b/chrome/browser/chromeos/printing/usb_printer_detector.h
index 3482ab97..205c94e 100644
--- a/chrome/browser/chromeos/printing/usb_printer_detector.h
+++ b/chrome/browser/chromeos/printing/usb_printer_detector.h
@@ -11,22 +11,15 @@
 
 #include "base/macros.h"
 #include "chrome/browser/chromeos/printing/printer_detector.h"
-#include "chromeos/printing/printer_configuration.h"
-#include "components/keyed_service/core/keyed_service.h"
-
-class Profile;
 
 namespace chromeos {
 
-// Observes device::UsbService for addition of USB printers.  When a new USB
-// printer that is not already configured for this user is found, if it can be
-// automatically configured for printing, that is done.  USB printers that
-// cannot be automatically configured are exposed via the PrinterDetector
-// interface so that higher level processing can handle them.
-class UsbPrinterDetector : public PrinterDetector, public KeyedService {
+// Observes device::UsbService for addition of USB printers, and implements the
+// PrinterDetector interface to export this to print system consumers.
+class UsbPrinterDetector : public PrinterDetector {
  public:
   // Factory function for the CUPS implementation.
-  static std::unique_ptr<UsbPrinterDetector> Create(Profile* profile);
+  static std::unique_ptr<UsbPrinterDetector> Create();
   ~UsbPrinterDetector() override = default;
 
  protected:
diff --git a/chrome/browser/chromeos/printing/usb_printer_detector_factory.cc b/chrome/browser/chromeos/printing/usb_printer_detector_factory.cc
deleted file mode 100644
index fc9b6647..0000000
--- a/chrome/browser/chromeos/printing/usb_printer_detector_factory.cc
+++ /dev/null
@@ -1,66 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chromeos/printing/usb_printer_detector_factory.h"
-
-#include "base/command_line.h"
-#include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
-#include "chrome/browser/chromeos/printing/usb_printer_detector.h"
-#include "chrome/browser/profiles/incognito_helpers.h"
-#include "chrome/browser/profiles/profile.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/keyed_service/content/browser_context_dependency_manager.h"
-#include "extensions/browser/extensions_browser_client.h"
-
-namespace chromeos {
-
-namespace {
-
-base::LazyInstance<UsbPrinterDetectorFactory>::DestructorAtExit g_factory =
-    LAZY_INSTANCE_INITIALIZER;
-
-}  // namespace
-
-// static
-UsbPrinterDetectorFactory* UsbPrinterDetectorFactory::GetInstance() {
-  return g_factory.Pointer();
-}
-
-UsbPrinterDetector* UsbPrinterDetectorFactory::Get(
-    content::BrowserContext* context) {
-  return static_cast<UsbPrinterDetector*>(
-      GetServiceForBrowserContext(context, false));
-}
-
-UsbPrinterDetectorFactory::UsbPrinterDetectorFactory()
-    : BrowserContextKeyedServiceFactory(
-          "UsbPrinterDetectorFactory",
-          BrowserContextDependencyManager::GetInstance()) {
-  DependsOn(
-      extensions::ExtensionsBrowserClient::Get()->GetExtensionSystemFactory());
-  DependsOn(SyncedPrintersManagerFactory::GetInstance());
-}
-
-UsbPrinterDetectorFactory::~UsbPrinterDetectorFactory() {}
-
-content::BrowserContext* UsbPrinterDetectorFactory::GetBrowserContextToUse(
-    content::BrowserContext* context) const {
-  return chrome::GetBrowserContextRedirectedInIncognito(context);
-}
-
-KeyedService* UsbPrinterDetectorFactory::BuildServiceInstanceFor(
-    content::BrowserContext* context) const {
-  return UsbPrinterDetector::Create(Profile::FromBrowserContext(context))
-      .release();
-}
-
-bool UsbPrinterDetectorFactory::ServiceIsCreatedWithBrowserContext() const {
-  return true;
-}
-
-bool UsbPrinterDetectorFactory::ServiceIsNULLWhileTesting() const {
-  return true;
-}
-
-}  // namespace chromeos
diff --git a/chrome/browser/chromeos/printing/usb_printer_detector_factory.h b/chrome/browser/chromeos/printing/usb_printer_detector_factory.h
deleted file mode 100644
index 8efd375..0000000
--- a/chrome/browser/chromeos/printing/usb_printer_detector_factory.h
+++ /dev/null
@@ -1,48 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHROMEOS_PRINTING_USB_PRINTER_DETECTOR_FACTORY_H_
-#define CHROME_BROWSER_CHROMEOS_PRINTING_USB_PRINTER_DETECTOR_FACTORY_H_
-
-#include "base/lazy_instance.h"
-#include "base/macros.h"
-#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
-#include "extensions/browser/extension_system_provider.h"
-
-namespace content {
-class BrowserContext;
-}
-
-namespace chromeos {
-
-class UsbPrinterDetector;
-
-class UsbPrinterDetectorFactory : public BrowserContextKeyedServiceFactory {
- public:
-  static UsbPrinterDetectorFactory* GetInstance();
-
-  UsbPrinterDetector* Get(content::BrowserContext* context);
-
- protected:
-  // BrowserContextKeyedServiceFactory:
-  content::BrowserContext* GetBrowserContextToUse(
-      content::BrowserContext* context) const override;
-
- private:
-  friend struct base::LazyInstanceTraitsBase<UsbPrinterDetectorFactory>;
-  UsbPrinterDetectorFactory();
-  ~UsbPrinterDetectorFactory() override;
-
-  // BrowserContextKeyedServiceFactory:
-  KeyedService* BuildServiceInstanceFor(
-      content::BrowserContext* browser_context) const override;
-  bool ServiceIsCreatedWithBrowserContext() const override;
-  bool ServiceIsNULLWhileTesting() const override;
-
-  DISALLOW_COPY_AND_ASSIGN(UsbPrinterDetectorFactory);
-};
-
-}  // namespace chromeos
-
-#endif  // CHROME_BROWSER_CHROMEOS_PRINTING_USB_PRINTER_DETECTOR_FACTORY_H_
diff --git a/chrome/browser/metrics/tab_stats_tracker.cc b/chrome/browser/metrics/tab_stats_tracker.cc
index 116ed2c..42b022e 100644
--- a/chrome/browser/metrics/tab_stats_tracker.cc
+++ b/chrome/browser/metrics/tab_stats_tracker.cc
@@ -32,7 +32,7 @@
 
 // static
 const char TabStatsTracker::kTabStatsDailyEventHistogramName[] =
-    "Tabs.TabsStatsDailyEventInteral";
+    "Tabs.TabsStatsDailyEventInterval";
 const char TabStatsTracker::UmaStatsReportingDelegate::
     kNumberOfTabsOnResumeHistogramName[] = "Tabs.NumberOfTabsOnResume";
 const char
@@ -157,6 +157,11 @@
 
 void TabStatsTracker::UmaStatsReportingDelegate::ReportDailyMetrics(
     const TabStatsDataStore::TabsStats& tab_stats) {
+  // Don't report the counts if they're equal to 0, this means that Chrome has
+  // only been running in the background since the last time the metrics have
+  // been reported.
+  if (tab_stats.total_tab_count_max == 0)
+    return;
   UMA_HISTOGRAM_COUNTS_10000(kMaxTabsInADayHistogramName,
                              tab_stats.total_tab_count_max);
   UMA_HISTOGRAM_COUNTS_10000(kMaxTabsPerWindowInADayHistogramName,
diff --git a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
index 0714a12..b6b28ea4 100644
--- a/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
+++ b/chrome/browser/offline_pages/prefetch/offline_prefetch_download_client.cc
@@ -53,8 +53,9 @@
 }
 
 void OfflinePrefetchDownloadClient::OnServiceUnavailable() {
-  // TODO(dtrainor, jianli): Handle service initialization failures.  This could
-  // potentially just drop all pending start requests.
+  PrefetchDownloader* downloader = GetPrefetchDownloader();
+  if (downloader)
+    downloader->OnDownloadServiceUnavailable();
 }
 
 download::Client::ShouldDownload
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index dcbd6d3..ee53f33 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -121,7 +121,6 @@
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/printing/cups_print_job_manager_factory.h"
 #include "chrome/browser/chromeos/printing/synced_printers_manager_factory.h"
-#include "chrome/browser/chromeos/printing/usb_printer_detector_factory.h"
 #include "chrome/browser/chromeos/tether/tether_service_factory.h"
 #include "chrome/browser/extensions/api/platform_keys/verify_trust_api.h"
 #endif
@@ -233,7 +232,6 @@
   EnhancedBookmarkKeyServiceFactory::GetInstance();
 #endif
 #if defined(OS_CHROMEOS)
-  chromeos::UsbPrinterDetectorFactory::GetInstance();
   chromeos::CupsPrintJobManagerFactory::GetInstance();
   chromeos::SyncedPrintersManagerFactory::GetInstance();
   TetherServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/md_extensions/compiled_resources2.gyp b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
index 7dc43376..3944f4c 100644
--- a/chrome/browser/resources/md_extensions/compiled_resources2.gyp
+++ b/chrome/browser/resources/md_extensions/compiled_resources2.gyp
@@ -191,7 +191,6 @@
       'dependencies': [
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
         '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior',
         'navigation_helper',
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
diff --git a/chrome/browser/resources/md_extensions/manager.js b/chrome/browser/resources/md_extensions/manager.js
index 9ac31f6..c11d0a6d 100644
--- a/chrome/browser/resources/md_extensions/manager.js
+++ b/chrome/browser/resources/md_extensions/manager.js
@@ -35,9 +35,6 @@
     behaviors: [I18nBehavior],
 
     properties: {
-      /** @type {extensions.Sidebar} */
-      sidebar: Object,
-
       /** @type {extensions.Toolbar} */
       toolbar: Object,
 
@@ -165,7 +162,19 @@
 
     /** @private */
     onMenuButtonTap_: function() {
-      this.$.drawer.toggle();
+      this.$.drawer.openDrawer();
+
+      // Sidebar needs manager to inform it of what to highlight since it
+      // has no access to item-specific page.
+      let page = extensions.navigation.getCurrentPage();
+      if (page.extensionId) {
+        // Find out what type of item we're looking at, and replace page info
+        // with that list type.
+        const data = assert(this.getData_(page.extensionId));
+        page = {page: Page.LIST, type: extensions.getItemListType(data)};
+      }
+
+      this.$.sidebar.updateSelected(page);
     },
 
     /**
@@ -298,7 +307,7 @@
         data = assert(this.getData_(newPage.extensionId));
 
       if (newPage.hasOwnProperty('type'))
-        this.listType_ = newPage.type;
+        this.listType_ = /** @type {extensions.ShowingType} */ (newPage.type);
 
       if (toPage == Page.DETAILS)
         this.detailViewItem_ = assert(data);
diff --git a/chrome/browser/resources/md_extensions/navigation_helper.js b/chrome/browser/resources/md_extensions/navigation_helper.js
index 768b9f1a..07d4d52 100644
--- a/chrome/browser/resources/md_extensions/navigation_helper.js
+++ b/chrome/browser/resources/md_extensions/navigation_helper.js
@@ -29,7 +29,8 @@
 
 /** @typedef {{page: Page,
                extensionId: (string|undefined),
-               subpage: (!Dialog|undefined)}} */
+               subpage: (!Dialog|undefined),
+               type: (!extensions.ShowingType|undefined)}} */
 let PageState;
 
 cr.define('extensions', function() {
@@ -117,7 +118,7 @@
       let path;
       switch (entry.page) {
         case Page.LIST:
-          if (entry.type && entry.type == extensions.ShowingType.APPS)
+          if (entry.type == extensions.ShowingType.APPS)
             path = '/apps';
           else
             path = '/';
diff --git a/chrome/browser/resources/md_extensions/sidebar.html b/chrome/browser/resources/md_extensions/sidebar.html
index 030c5c1..14698c8 100644
--- a/chrome/browser/resources/md_extensions/sidebar.html
+++ b/chrome/browser/resources/md_extensions/sidebar.html
@@ -50,7 +50,7 @@
         width: 15px;
       }
     </style>
-    <paper-menu id="section-menu" selected="0">
+    <paper-menu id="section-menu" selected="{{selected_}}">
       <paper-item class="section-item" id="sections-extensions"
           on-tap="onExtensionsTap_">
         <span>$i18n{sidebarExtensions}</span>
diff --git a/chrome/browser/resources/md_extensions/sidebar.js b/chrome/browser/resources/md_extensions/sidebar.js
index c81d919..afb14a5 100644
--- a/chrome/browser/resources/md_extensions/sidebar.js
+++ b/chrome/browser/resources/md_extensions/sidebar.js
@@ -5,7 +5,13 @@
   const Sidebar = Polymer({
     is: 'extensions-sidebar',
 
-    behaviors: [I18nBehavior],
+    properties: {
+      /** @private {number} */
+      selected_: {
+        type: Number,
+        value: -1,
+      },
+    },
 
     /** @private */
     onExtensionsTap_: function() {
@@ -23,6 +29,30 @@
     onKeyboardShortcutsTap_: function() {
       extensions.navigation.navigateTo({page: Page.SHORTCUTS});
     },
+
+    /**
+     * @param {!PageState} state
+     */
+    updateSelected: function(state) {
+      let selected;
+
+      switch (state.page) {
+        case Page.LIST:
+          if (state.type == extensions.ShowingType.APPS)
+            selected = 1;
+          else
+            selected = 0;
+          break;
+        case Page.SHORTCUTS:
+          selected = 2;
+          break;
+        default:
+          selected = -1;
+          break;
+      }
+
+      this.selected_ = selected;
+    },
   });
 
   return {Sidebar: Sidebar};
diff --git a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
index 67ac283..7f8a980 100644
--- a/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
+++ b/chrome/browser/resources/ssl/ssl_error_assistant/ssl_error_assistant.asciipb
@@ -6,7 +6,7 @@
 # certificates. See chrome/browser/ssl/ssl_error_assistant.proto for the full
 # format.
 
-version_id: 3
+version_id: 4
 
 # https://captive-portal.badssl.com leaf.
 # This is a test certificate, always keep it at the top.
@@ -155,8 +155,7 @@
 # This is a test certificate, keep it at the top of the MITM software list.
 mitm_software {
   name: "BadSSL Antivirus",
-  issuer_common_name_regex: "BadSSL MITM Software Test",
-  issuer_organization_regex: "BadSSL"
+  issuer_common_name_regex: "BadSSL MITM Software Test"
 }
 
 ################################################################################
diff --git a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
index cdc21d4..b224f343 100644
--- a/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
+++ b/chrome/browser/ui/content_settings/content_setting_bubble_model_unittest.cc
@@ -395,8 +395,8 @@
               bubble_content.media_menus.begin()->first);
     EXPECT_FALSE(bubble_content.media_menus.begin()->second.disabled);
     // The first audio device should be selected by default.
-    EXPECT_TRUE(fake_audio_device1.IsEqual(
-                bubble_content.media_menus.begin()->second.selected_device));
+    EXPECT_TRUE(fake_audio_device1.IsSameDevice(
+        bubble_content.media_menus.begin()->second.selected_device));
 
     // Select a different (the second) device.
     content_setting_bubble_model->OnMediaMenuClicked(
@@ -414,8 +414,8 @@
               bubble_content.media_menus.begin()->first);
     EXPECT_FALSE(bubble_content.media_menus.begin()->second.disabled);
     // The second audio device should be selected.
-    EXPECT_TRUE(fake_audio_device2.IsEqual(
-                bubble_content.media_menus.begin()->second.selected_device));
+    EXPECT_TRUE(fake_audio_device2.IsSameDevice(
+        bubble_content.media_menus.begin()->second.selected_device));
     // The "settings changed" message should not be displayed when there is no
     // active capture.
     EXPECT_FALSE(bubble_content.custom_link_enabled);
@@ -451,8 +451,8 @@
     EXPECT_EQ(content::MEDIA_DEVICE_AUDIO_CAPTURE,
               bubble_content.media_menus.begin()->first);
     EXPECT_FALSE(bubble_content.media_menus.begin()->second.disabled);
-    EXPECT_TRUE(fake_audio_device2.IsEqual(
-                bubble_content.media_menus.begin()->second.selected_device));
+    EXPECT_TRUE(fake_audio_device2.IsSameDevice(
+        bubble_content.media_menus.begin()->second.selected_device));
 
     // Select a different different device.
     content_setting_bubble_model->OnMediaMenuClicked(
@@ -498,8 +498,8 @@
     EXPECT_EQ(content::MEDIA_DEVICE_AUDIO_CAPTURE,
               bubble_content.media_menus.begin()->first);
     EXPECT_FALSE(bubble_content.media_menus.begin()->second.disabled);
-    EXPECT_TRUE(fake_audio_device3.IsEqual(
-                bubble_content.media_menus.begin()->second.selected_device));
+    EXPECT_TRUE(fake_audio_device3.IsSameDevice(
+        bubble_content.media_menus.begin()->second.selected_device));
   }
 }
 
diff --git a/chrome/browser/vr/animation_player.cc b/chrome/browser/vr/animation_player.cc
index 5bbe34a..69c043d 100644
--- a/chrome/browser/vr/animation_player.cc
+++ b/chrome/browser/vr/animation_player.cc
@@ -8,8 +8,8 @@
 
 #include "base/stl_util.h"
 #include "cc/animation/animation_curve.h"
-#include "cc/animation/animation_player.h"
 #include "cc/animation/animation_target.h"
+#include "cc/animation/animation_ticker.h"
 #include "cc/animation/keyframed_animation_curve.h"
 #include "cc/base/math_util.h"
 #include "chrome/browser/vr/elements/ui_element.h"
@@ -154,7 +154,7 @@
   StartAnimations(monotonic_time);
 
   for (auto& animation : animations_) {
-    cc::AnimationPlayer::TickAnimation(monotonic_time, animation.get(),
+    cc::AnimationTicker::TickAnimation(monotonic_time, animation.get(),
                                        target_);
   }
 
diff --git a/chrome/browser/vr/elements/ui_element.cc b/chrome/browser/vr/elements/ui_element.cc
index b9e2d47..08010c2 100644
--- a/chrome/browser/vr/elements/ui_element.cc
+++ b/chrome/browser/vr/elements/ui_element.cc
@@ -94,6 +94,11 @@
 void UiElement::SetVisible(bool visible) {
   SetOpacity(visible ? opacity_when_visible_ : 0.0);
 }
+
+void UiElement::SetVisibleImmediately(bool visible) {
+  opacity_ = visible ? opacity_when_visible_ : 0.0;
+}
+
 bool UiElement::IsVisible() const {
   return opacity_ > 0.0f && computed_opacity_ > 0.0f;
 }
diff --git a/chrome/browser/vr/elements/ui_element.h b/chrome/browser/vr/elements/ui_element.h
index 56b6be023..99417b0 100644
--- a/chrome/browser/vr/elements/ui_element.h
+++ b/chrome/browser/vr/elements/ui_element.h
@@ -105,6 +105,7 @@
   bool IsVisible() const;
   // For convenience, sets opacity to |opacity_when_visible_|.
   virtual void SetVisible(bool visible);
+  void SetVisibleImmediately(bool visible);
 
   void set_opacity_when_visible(float opacity) {
     opacity_when_visible_ = opacity;
diff --git a/chrome/browser/vr/elements/viewport_aware_root.cc b/chrome/browser/vr/elements/viewport_aware_root.cc
index 7a1139d..fbae99a 100644
--- a/chrome/browser/vr/elements/viewport_aware_root.cc
+++ b/chrome/browser/vr/elements/viewport_aware_root.cc
@@ -6,6 +6,8 @@
 
 #include <cmath>
 
+#include "cc/base/math_util.h"
+
 namespace vr {
 
 // static
@@ -13,6 +15,7 @@
 
 ViewportAwareRoot::ViewportAwareRoot() {
   set_viewport_aware(true);
+  SetTransitionedProperties({OPACITY});
 }
 
 ViewportAwareRoot::~ViewportAwareRoot() = default;
@@ -20,21 +23,27 @@
 void ViewportAwareRoot::AdjustRotationForHeadPose(
     const gfx::Vector3dF& look_at) {
   DCHECK(viewport_aware());
+  DCHECK(!look_at.IsZero());
 
   gfx::Vector3dF rotated_center_vector{0.f, 0.f, -1.0f};
   LocalTransform().TransformVector(&rotated_center_vector);
   gfx::Vector3dF top_projected_look_at{look_at.x(), 0.f, look_at.z()};
   float degrees = gfx::ClockwiseAngleBetweenVectorsInDegrees(
       top_projected_look_at, rotated_center_vector, {0.f, 1.0f, 0.f});
-  if (degrees > kViewportRotationTriggerDegrees &&
-      degrees < 360.0f - kViewportRotationTriggerDegrees) {
-    viewport_aware_total_rotation_ += degrees;
-    if (viewport_aware_total_rotation_ > 360.0f)
-      viewport_aware_total_rotation_ -= 360.0f;
-    if (viewport_aware_total_rotation_ < -360.0f)
-      viewport_aware_total_rotation_ += 360.0f;
-    SetRotate(0.f, 1.f, 0.f, viewport_aware_total_rotation_ / 180 * M_PI);
+  if (degrees <= kViewportRotationTriggerDegrees ||
+      degrees >= 360.0f - kViewportRotationTriggerDegrees) {
+    return;
   }
+  viewport_aware_total_rotation_ += degrees;
+  viewport_aware_total_rotation_ = fmod(viewport_aware_total_rotation_, 360.0f);
+  SetRotate(0.f, 1.f, 0.f,
+            cc::MathUtil::Deg2Rad(viewport_aware_total_rotation_));
+
+  // Immediately hide the element.
+  SetVisibleImmediately(false);
+
+  // Fade it back in.
+  SetVisible(true);
 }
 
 void ViewportAwareRoot::OnUpdatedInheritedProperties() {
diff --git a/chrome/browser/vr/elements/viewport_aware_root_unittest.cc b/chrome/browser/vr/elements/viewport_aware_root_unittest.cc
index 17f96dc..8e7fa27f1 100644
--- a/chrome/browser/vr/elements/viewport_aware_root_unittest.cc
+++ b/chrome/browser/vr/elements/viewport_aware_root_unittest.cc
@@ -20,6 +20,7 @@
 namespace {
 
 const float kThreshold = ViewportAwareRoot::kViewportRotationTriggerDegrees;
+const int kFramesPerSecond = 60;
 
 bool FloatNearlyEqual(float a, float b) {
   return std::abs(a - b) < kEpsilon;
@@ -110,31 +111,78 @@
       gfx::Vector3dF{0.f, -std::sin(1.5), -std::cos(1.5)});
 }
 
-TEST(ViewportAwareRoot, ChildElementsRepositioned) {
-  UiScene scene;
+class ViewportAwareRootTest : public testing::Test {
+ public:
+  ViewportAwareRootTest() {}
+  ~ViewportAwareRootTest() override {}
 
-  auto viewport_aware_root = base::MakeUnique<ViewportAwareRoot>();
-  ViewportAwareRoot& root = *viewport_aware_root;
-  root.set_draw_phase(kPhaseForeground);
-  scene.AddUiElement(kRoot, std::move(viewport_aware_root));
+  void SetUp() override {
+    scene_ = base::MakeUnique<UiScene>();
+    auto viewport_aware_root = base::MakeUnique<ViewportAwareRoot>();
+    viewport_aware_root->set_draw_phase(kPhaseForeground);
+    viewport_root = viewport_aware_root.get();
+    scene_->AddUiElement(kRoot, std::move(viewport_aware_root));
 
-  auto element = base::MakeUnique<UiElement>();
-  UiElement& child = *element;
-  element->set_viewport_aware(true);
-  element->set_draw_phase(kPhaseForeground);
-  element->SetTranslate(0.f, 0.f, -1.f);
-  root.AddChild(std::move(element));
+    auto element = base::MakeUnique<UiElement>();
+    element->set_viewport_aware(true);
+    element->set_draw_phase(kPhaseForeground);
+    element->SetTranslate(0.f, 0.f, -1.f);
+    viewport_element = element.get();
+    viewport_root->AddChild(std::move(element));
+  }
 
+ protected:
+  void AnimateWithHeadPose(base::TimeDelta delta,
+                           const gfx::Vector3dF& head_pose) {
+    base::TimeTicks target_time = current_time_ + delta;
+    base::TimeDelta frame_duration =
+        base::TimeDelta::FromSecondsD(1.0 / kFramesPerSecond);
+    for (; current_time_ < target_time; current_time_ += frame_duration) {
+      scene_->OnBeginFrame(current_time_, head_pose);
+    }
+    current_time_ = target_time;
+    scene_->OnBeginFrame(current_time_, head_pose);
+  }
+
+  UiElement* viewport_root;
+  UiElement* viewport_element;
+
+ private:
+  std::unique_ptr<UiScene> scene_;
+  base::TimeTicks current_time_;
+};
+
+TEST_F(ViewportAwareRootTest, ChildElementsRepositioned) {
   gfx::Vector3dF look_at{0.f, 0.f, -1.f};
-  scene.OnBeginFrame(MicrosecondsToTicks(0), look_at);
-  EXPECT_TRUE(
-      Point3FAreNearlyEqual(gfx::Point3F(0.f, 0.f, -1.f), child.GetCenter()));
+  AnimateWithHeadPose(MsToDelta(0), look_at);
+  EXPECT_TRUE(Point3FAreNearlyEqual(gfx::Point3F(0.f, 0.f, -1.f),
+                                    viewport_element->GetCenter()));
 
   // This should trigger reposition of viewport aware elements.
   RotateAboutYAxis(90.f, &look_at);
-  scene.OnBeginFrame(MicrosecondsToTicks(10), look_at);
-  EXPECT_TRUE(
-      Point3FAreNearlyEqual(gfx::Point3F(-1.f, 0.f, 0.f), child.GetCenter()));
+  AnimateWithHeadPose(MsToDelta(10), look_at);
+  EXPECT_TRUE(Point3FAreNearlyEqual(gfx::Point3F(-1.f, 0.f, 0.f),
+                                    viewport_element->GetCenter()));
+}
+
+TEST_F(ViewportAwareRootTest, ChildElementsHasOpacityAnimation) {
+  gfx::Vector3dF look_at{0.f, 0.f, -1.f};
+  AnimateWithHeadPose(MsToDelta(0), look_at);
+  EXPECT_TRUE(viewport_element->IsVisible());
+
+  // Trigger a reposition.
+  RotateAboutYAxis(90.f, &look_at);
+  AnimateWithHeadPose(MsToDelta(5), look_at);
+
+  // Initially the element should be invisible and then animate to its full
+  // opacity.
+  EXPECT_FALSE(viewport_element->IsVisible());
+  AnimateWithHeadPose(MsToDelta(50), look_at);
+  EXPECT_TRUE(viewport_element->IsVisible());
+  EXPECT_TRUE(IsAnimating(viewport_root, {OPACITY}));
+  AnimateWithHeadPose(MsToDelta(500), look_at);
+  EXPECT_TRUE(viewport_element->IsVisible());
+  EXPECT_FALSE(IsAnimating(viewport_root, {OPACITY}));
 }
 
 }  // namespace vr
diff --git a/chrome/browser/vr/test/animation_utils.cc b/chrome/browser/vr/test/animation_utils.cc
index 7f78656..6848ea9 100644
--- a/chrome/browser/vr/test/animation_utils.cc
+++ b/chrome/browser/vr/test/animation_utils.cc
@@ -4,7 +4,8 @@
 
 #include "chrome/browser/vr/test/animation_utils.h"
 
-#include "chrome/browser/vr/target_property.h"
+#include "chrome/browser/vr/animation_player.h"
+#include "chrome/browser/vr/elements/ui_element.h"
 
 namespace vr {
 
@@ -56,4 +57,13 @@
   return MicrosecondsToDelta(1000 * ms);
 }
 
+bool IsAnimating(UiElement* element,
+                 const std::vector<TargetProperty>& properties) {
+  for (auto property : properties) {
+    if (!element->animation_player().IsAnimatingProperty(property))
+      return false;
+  }
+  return true;
+}
+
 }  // namespace vr
diff --git a/chrome/browser/vr/test/animation_utils.h b/chrome/browser/vr/test/animation_utils.h
index 9cf52a3..4ed3310 100644
--- a/chrome/browser/vr/test/animation_utils.h
+++ b/chrome/browser/vr/test/animation_utils.h
@@ -5,11 +5,16 @@
 #ifndef CHROME_BROWSER_VR_TEST_ANIMATION_UTILS_H_
 #define CHROME_BROWSER_VR_TEST_ANIMATION_UTILS_H_
 
+#include <vector>
+
 #include "cc/animation/animation.h"
 #include "cc/animation/keyframed_animation_curve.h"
+#include "chrome/browser/vr/target_property.h"
 
 namespace vr {
 
+class UiElement;
+
 std::unique_ptr<cc::Animation> CreateTransformAnimation(
     int id,
     int group,
@@ -29,6 +34,10 @@
 base::TimeTicks MsToTicks(uint64_t us);
 base::TimeDelta MsToDelta(uint64_t us);
 
+// Returns true if the given properties are being animated by the element.
+bool IsAnimating(UiElement* element,
+                 const std::vector<TargetProperty>& properties);
+
 }  // namespace vr
 
 #endif  // CHROME_BROWSER_VR_TEST_ANIMATION_UTILS_H_
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.cc b/chrome/browser/vr/test/ui_scene_manager_test.cc
index 326b6744..0e0dc8d 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.cc
+++ b/chrome/browser/vr/test/ui_scene_manager_test.cc
@@ -103,20 +103,10 @@
   base::TimeTicks target_time = current_time_ + delta;
   base::TimeDelta frame_time = base::TimeDelta::FromSecondsD(1.0 / 60.0);
   for (; current_time_ < target_time; current_time_ += frame_time) {
-    scene_->OnBeginFrame(current_time_, gfx::Vector3dF());
+    scene_->OnBeginFrame(current_time_, gfx::Vector3dF(0.f, 0.f, -1.0f));
   }
   current_time_ = target_time;
-  scene_->OnBeginFrame(current_time_, gfx::Vector3dF());
-}
-
-bool UiSceneManagerTest::IsAnimating(
-    UiElement* element,
-    const std::vector<TargetProperty>& properties) const {
-  for (auto property : properties) {
-    if (!element->animation_player().IsAnimatingProperty(property))
-      return false;
-  }
-  return true;
+  scene_->OnBeginFrame(current_time_, gfx::Vector3dF(0.f, 0.f, -1.0f));
 }
 
 SkColor UiSceneManagerTest::GetBackgroundColor() const {
diff --git a/chrome/browser/vr/test/ui_scene_manager_test.h b/chrome/browser/vr/test/ui_scene_manager_test.h
index 2c3830c..e576bd7 100644
--- a/chrome/browser/vr/test/ui_scene_manager_test.h
+++ b/chrome/browser/vr/test/ui_scene_manager_test.h
@@ -10,7 +10,6 @@
 #include "base/macros.h"
 #include "base/message_loop/message_loop.h"
 #include "chrome/browser/vr/elements/ui_element_name.h"
-#include "chrome/browser/vr/target_property.h"
 #include "chrome/browser/vr/test/mock_browser_interface.h"
 #include "chrome/browser/vr/test/mock_content_input_delegate.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -18,7 +17,6 @@
 
 namespace vr {
 
-class UiElement;
 class UiScene;
 class UiSceneManager;
 
@@ -68,10 +66,6 @@
   // UiScene::OnBeginFrame is called at each increment.
   void AnimateBy(base::TimeDelta delta);
 
-  // Returns true if the given properties are being animated by the element.
-  bool IsAnimating(UiElement* element,
-                   const std::vector<TargetProperty>& properties) const;
-
   SkColor GetBackgroundColor() const;
 
   base::MessageLoop message_loop_;
diff --git a/chrome/browser/vr/ui_input_manager_unittest.cc b/chrome/browser/vr/ui_input_manager_unittest.cc
index c2a0f6e9..f2ce88f 100644
--- a/chrome/browser/vr/ui_input_manager_unittest.cc
+++ b/chrome/browser/vr/ui_input_manager_unittest.cc
@@ -26,7 +26,8 @@
     UiSceneManagerTest::SetUp();
     MakeManager(kNotInCct, kNotInWebVr);
     input_manager_ = base::MakeUnique<UiInputManager>(scene_.get());
-    scene_->OnBeginFrame(MicrosecondsToTicks(1), gfx::Vector3dF());
+    scene_->OnBeginFrame(MicrosecondsToTicks(1),
+                         gfx::Vector3dF(0.f, 0.f, -1.0f));
   }
 
  protected:
diff --git a/chrome/browser/vr/ui_scene_unittest.cc b/chrome/browser/vr/ui_scene_unittest.cc
index 2987ee0..71b57d8 100644
--- a/chrome/browser/vr/ui_scene_unittest.cc
+++ b/chrome/browser/vr/ui_scene_unittest.cc
@@ -115,7 +115,7 @@
   gfx::Point3F origin(0, 0, 0);
   gfx::Point3F point(1, 0, 0);
 
-  scene.OnBeginFrame(MicrosecondsToTicks(1), gfx::Vector3dF());
+  scene.OnBeginFrame(MicrosecondsToTicks(1), gfx::Vector3dF(0.f, 0.f, -1.0f));
   child->world_space_transform().TransformPoint(&origin);
   child->world_space_transform().TransformPoint(&point);
   EXPECT_VEC3F_NEAR(gfx::Point3F(6, 10, 0), origin);
@@ -137,7 +137,7 @@
   element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
-  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF());
+  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF(0.f, 0.f, -1.0f));
   EXPECT_EQ(0.5f, parent->computed_opacity());
   EXPECT_EQ(0.25f, child->computed_opacity());
 }
@@ -162,7 +162,7 @@
   element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
-  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF());
+  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF(0.f, 0.f, -1.0f));
   EXPECT_TRUE(parent->computed_viewport_aware());
   EXPECT_TRUE(child->computed_viewport_aware());
 }
@@ -195,7 +195,7 @@
   element->set_draw_phase(0);
   parent->AddChild(std::move(element));
 
-  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF());
+  scene.OnBeginFrame(MicrosecondsToTicks(0), gfx::Vector3dF(0.f, 0.f, -1.0f));
   EXPECT_NEAR(GetParam().expected_x, child->GetCenter().x(), TOLERANCE);
   EXPECT_NEAR(GetParam().expected_y, child->GetCenter().y(), TOLERANCE);
 }
diff --git a/chrome/profiling/README.md b/chrome/profiling/README.md
index 098aa3b..c3bcd1e 100644
--- a/chrome/profiling/README.md
+++ b/chrome/profiling/README.md
@@ -1,22 +1,37 @@
 # chrome/profiling
 
 This document describes the architecture for the profiling process, which
-tracks memory allocations in other processes.
+tracks memory allocations in other processes. See [design doc] for more details.
 
-Design doc: https://docs.google.com/document/d/1eRAgOFgHwYEPge8G1_5UEvu8TJs5VkYCxd6aFU8AIKY
+[design doc]: https://docs.google.com/document/d/1eRAgOFgHwYEPge8G1_5UEvu8TJs5VkYCxd6aFU8AIKY
 
 How To Enable Out of Process Heap Profiling
 -------------------------------------------
-On Windows, build a static, release binary.
+Navigate to `chrome://flags/#memlog` and set the flag to
+"Profile only the browser process." It's possible to profile all processes, but
+that has a higher performance impact, and heap dumps of renderer processes are
+less actionable.
 
-When starting Chrome, pass the command line flag `--memlog=browser` to profile
-just the browser process, or `--memlog=all` to profile all processes. Navigate
-to `chrome://memory-internals`, and press the "Dump" button to trigger a memory
-dump for a given process. This creates a dump called `memlog_dump.json.gz` in
-the profile directory.
+How To Use Out of Process Heap Profiling
+-------------------------------------------
+By default, you don't need to do anything. The heap profiler will detect when
+the browser's memory usage has exceeded a certain threshold and upload a trace.
 
-The `--memlog` flag is also exposed in chrome://flags/#memlog
+To force an upload, or to create a heap dump manually, see
+`chrome://memory-internals`. The resulting heap dump is intended to be used with
+[symbolize_trace][1] and [diff_heap_profiler.py][2].
 
+It's also possible to view the heap dump within a [memory-infra][3] trace,
+although the results will still need to be symbolized with [symbolize_trace][1].
+
+Due to size constraints, most allocations are pruned from the heap dump. Only
+allocations of sufficient size and/or frequency are kept. After pruning, the
+result is ~100x smaller, but still accounts for about half of all allocations.
+More importantly, it still accounts for all obvious memory leaks.
+
+[1]: https://cs.chromium.org/chromium/src/third_party/catapult/tracing/bin/symbolize_trace
+[2]: https://cs.chromium.org/chromium/src/third_party/catapult/experimental/tracing/bin/diff_heap_profiler.py
+[3]: /docs/memory-infra/README.md
 
 Communication Model
 -------------------
diff --git a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
index 4307eec..26c587e 100644
--- a/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
+++ b/chrome/test/data/webui/extensions/cr_extensions_browsertest.js
@@ -66,6 +66,11 @@
 
 var CrExtensionsSidebarTest = class extends CrExtensionsBrowserTest {
   /** @override */
+  get browsePreload() {
+    return 'chrome://extensions/sidebar.html';
+  }
+
+  /** @override */
   get extraLibraries() {
     return super.extraLibraries.concat([
       'extension_sidebar_test.js',
@@ -78,6 +83,10 @@
       .run();
 });
 
+TEST_F('CrExtensionsSidebarTest', 'UpdateSelected', function() {
+  mocha.grep(assert(extension_sidebar_tests.TestNames.UpdateSelected)).run();
+});
+
 ////////////////////////////////////////////////////////////////////////////////
 // Extension Toolbar Tests
 
@@ -321,6 +330,13 @@
     });
 
 TEST_F(
+    'CrExtensionsManagerTestWithMultipleExtensionTypesInstalled',
+    'SidebarHighlighting', function() {
+      mocha.grep(assert(extension_manager_tests.TestNames.SidebarHighlighting))
+          .run();
+    });
+
+TEST_F(
     'CrExtensionsManagerTestWithIdQueryParam', 'NavigationToDetails',
     function() {
       mocha
diff --git a/chrome/test/data/webui/extensions/extension_manager_test.js b/chrome/test/data/webui/extensions/extension_manager_test.js
index 0a21c39..f640891 100644
--- a/chrome/test/data/webui/extensions/extension_manager_test.js
+++ b/chrome/test/data/webui/extensions/extension_manager_test.js
@@ -12,6 +12,7 @@
     ChangePages: 'change pages',
     UrlNavigationToDetails: 'url navigation to details',
     UpdateItemData: 'update item data',
+    SidebarHighlighting: 'sidebar highlighting',
   };
 
   function getDataByName(list, name) {
@@ -129,6 +130,46 @@
       expectEquals(manager.extensions, manager.$['items-list'].items);
     });
 
+    test(assert(TestNames.SidebarHighlighting), function() {
+      const toolbar = manager.$$('extensions-toolbar');
+
+      // Stub manager.$.sidebar for testing convenience.
+      let pageState;
+      manager.$.sidebar = {
+        updateSelected: function(state) {
+          pageState = state;
+        },
+      };
+
+      // Tests if manager calls sidebar.updateSelected with the right params.
+      function testPassingCorrectState(onPageState, passedPageState) {
+        extensions.navigation.navigateTo(onPageState);
+        toolbar.fire('cr-toolbar-menu-tap');
+        expectDeepEquals(pageState, passedPageState || onPageState);
+        // Reset pageState so that testing order doesn't matter.
+        pageState = null;
+      }
+
+      testPassingCorrectState({page: Page.SHORTCUTS});
+      testPassingCorrectState(
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
+      testPassingCorrectState(
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+
+      testPassingCorrectState(
+          {page: Page.DETAILS, extensionId: manager.apps[0].id},
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
+      testPassingCorrectState(
+          {page: Page.DETAILS, extensionId: manager.extensions[0].id},
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+      testPassingCorrectState(
+          {page: Page.ERRORS, extensionId: manager.apps[0].id},
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
+      testPassingCorrectState(
+          {page: Page.ERRORS, extensionId: manager.extensions[0].id},
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+    });
+
     test(assert(TestNames.ChangePages), function() {
       // We start on the item list.
       MockInteractions.tap(manager.$.sidebar.$['sections-extensions']);
diff --git a/chrome/test/data/webui/extensions/extension_sidebar_test.js b/chrome/test/data/webui/extensions/extension_sidebar_test.js
index 15c66c5..e998821e 100644
--- a/chrome/test/data/webui/extensions/extension_sidebar_test.js
+++ b/chrome/test/data/webui/extensions/extension_sidebar_test.js
@@ -7,21 +7,33 @@
   /** @enum {string} */
   var TestNames = {
     LayoutAndClickHandlers: 'layout and click handlers',
+    UpdateSelected: 'update selected',
   };
 
   suite('ExtensionSidebarTest', function() {
     /** @type {extensions.Sidebar} */
     var sidebar;
 
-    // Import cr_settings_checkbox.html before running suite.
-    suiteSetup(function() {
-      return PolymerTest.importHtml('chrome://extensions/sidebar.html');
+    setup(function() {
+      PolymerTest.clearBody();
+      sidebar = new extensions.Sidebar();
+      document.body.appendChild(sidebar);
     });
 
-    setup(function() {
-      var manager = document.querySelector('extensions-manager');
-      manager.$.drawer.openDrawer();
-      sidebar = manager.$.sidebar;
+    test(assert(TestNames.UpdateSelected), function() {
+      const selector = 'paper-item.iron-selected';
+      expectFalse(!!sidebar.$$(selector));
+
+      sidebar.updateSelected({page: Page.SHORTCUTS});
+      expectEquals(sidebar.$$(selector).id, 'sections-shortcuts');
+
+      sidebar.updateSelected(
+          {page: Page.LIST, type: extensions.ShowingType.APPS});
+      expectEquals(sidebar.$$(selector).id, 'sections-apps');
+
+      sidebar.updateSelected(
+          {page: Page.LIST, type: extensions.ShowingType.EXTENSIONS});
+      expectEquals(sidebar.$$(selector).id, 'sections-extensions');
     });
 
     test(assert(TestNames.LayoutAndClickHandlers), function() {
diff --git a/components/download/internal/test/test_download_service.cc b/components/download/internal/test/test_download_service.cc
index ce2cb38..7b5aa2f 100644
--- a/components/download/internal/test/test_download_service.cc
+++ b/components/download/internal/test/test_download_service.cc
@@ -61,21 +61,19 @@
 }
 
 void TestDownloadService::StartDownload(const DownloadParams& params) {
-  if (!is_ready_) {
-    params.callback.Run(params.guid,
-                        DownloadParams::StartResult::INTERNAL_ERROR);
-    return;
-  }
-
   if (!failed_download_id_.empty() && fail_at_start_) {
     params.callback.Run(params.guid,
                         DownloadParams::StartResult::UNEXPECTED_GUID);
     return;
   }
 
+  // The download will be accepted and queued even if the service is not ready.
   params.callback.Run(params.guid, DownloadParams::StartResult::ACCEPTED);
-
   downloads_.push_back(params);
+
+  if (!is_ready_)
+    return;
+
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(&TestDownloadService::ProcessDownload,
                             base::Unretained(this)));
@@ -114,6 +112,12 @@
   fail_at_start_ = fail_at_start;
 }
 
+void TestDownloadService::SetIsReady(bool is_ready) {
+  is_ready_ = is_ready;
+  if (is_ready_)
+    ProcessDownload();
+}
+
 void TestDownloadService::ProcessDownload() {
   DCHECK(!fail_at_start_);
   if (!is_ready_ || downloads_.empty())
diff --git a/components/download/internal/test/test_download_service.h b/components/download/internal/test/test_download_service.h
index 96e1dd24..146839c 100644
--- a/components/download/internal/test/test_download_service.h
+++ b/components/download/internal/test/test_download_service.h
@@ -43,7 +43,7 @@
   void SetFailedDownload(const std::string& failed_download_id,
                          bool fail_at_start);
 
-  void set_is_ready(bool is_ready) { is_ready_ = is_ready; }
+  void SetIsReady(bool is_ready);
 
   void set_client(Client* client) { client_ = client; }
 
diff --git a/components/exo/BUILD.gn b/components/exo/BUILD.gn
index 41a6440c..7689e5e 100644
--- a/components/exo/BUILD.gn
+++ b/components/exo/BUILD.gn
@@ -64,7 +64,6 @@
     "//ash/public/cpp:ash_public_cpp",
     "//base",
     "//cc",
-    "//cc/ipc:interfaces",
     "//components/viz/service",
     "//device/gamepad",
     "//device/gamepad/public/cpp:shared_with_blink",
diff --git a/components/exo/surface.cc b/components/exo/surface.cc
index 0e87b933..8c2812c 100644
--- a/components/exo/surface.cc
+++ b/components/exo/surface.cc
@@ -724,7 +724,7 @@
   // Surface uses DIP, but the |render_pass->damage_rect| uses pixels, so we
   // need scale it beased on the |device_scale_factor|.
   gfx::Rect damage_rect = gfx::SkIRectToRect(damage_.getBounds());
-  damage_rect.set_origin(origin);
+  damage_rect.Offset(origin.x(), origin.y());
   render_pass->damage_rect.Union(
       gfx::ConvertRectToPixel(device_scale_factor, damage_rect));
 
diff --git a/components/exo/surface_unittest.cc b/components/exo/surface_unittest.cc
index 9ee29738..9417c1f 100644
--- a/components/exo/surface_unittest.cc
+++ b/components/exo/surface_unittest.cc
@@ -100,11 +100,23 @@
   ASSERT_EQ(1, release_buffer_call_count);
 }
 
+const cc::CompositorFrame& GetFrameFromSurface(ShellSurface* shell_surface) {
+  viz::SurfaceId surface_id = shell_surface->host_window()->GetSurfaceId();
+  viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
+                                             ->context_factory_private()
+                                             ->GetFrameSinkManager()
+                                             ->surface_manager();
+  const cc::CompositorFrame& frame =
+      surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
+  return frame;
+}
+
 TEST_P(SurfaceTest, Damage) {
   gfx::Size buffer_size(256, 256);
   std::unique_ptr<Buffer> buffer(
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   std::unique_ptr<Surface> surface(new Surface);
+  auto shell_surface = base::MakeUnique<ShellSurface>(surface.get());
 
   // Attach the buffer to the surface. This will update the pending bounds of
   // the surface to the buffer size.
@@ -121,6 +133,24 @@
   // Check that damage larger than contents is handled correctly at commit.
   surface->Damage(gfx::Rect(gfx::ScaleToCeiledSize(buffer_size, 2.0f)));
   surface->Commit();
+  RunAllPendingInMessageLoop();
+
+  {
+    const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+    EXPECT_EQ(ToPixel(gfx::Rect(0, 0, 512, 512)),
+              frame.render_pass_list.back()->damage_rect);
+  }
+
+  // Check that damage is correct for a non-square rectangle not at the origin.
+  surface->Damage(gfx::Rect(64, 128, 16, 32));
+  surface->Commit();
+  RunAllPendingInMessageLoop();
+
+  {
+    const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
+    EXPECT_EQ(ToPixel(gfx::Rect(64, 128, 16, 32)),
+              frame.render_pass_list.back()->damage_rect);
+  }
 }
 
 void SetFrameTime(base::TimeTicks* result, base::TimeTicks frame_time) {
@@ -139,17 +169,6 @@
   EXPECT_TRUE(frame_time.is_null());
 }
 
-const cc::CompositorFrame& GetFrameFromSurface(ShellSurface* shell_surface) {
-  viz::SurfaceId surface_id = shell_surface->host_window()->GetSurfaceId();
-  viz::SurfaceManager* surface_manager = aura::Env::GetInstance()
-                                             ->context_factory_private()
-                                             ->GetFrameSinkManager()
-                                             ->surface_manager();
-  const cc::CompositorFrame& frame =
-      surface_manager->GetSurfaceForId(surface_id)->GetActiveFrame();
-  return frame;
-}
-
 TEST_P(SurfaceTest, SetOpaqueRegion) {
   gfx::Size buffer_size(1, 1);
   auto buffer = base::MakeUnique<Buffer>(
@@ -439,8 +458,8 @@
   const cc::CompositorFrame& frame = GetFrameFromSurface(shell_surface.get());
   ASSERT_EQ(1u, frame.render_pass_list.size());
   ASSERT_EQ(1u, frame.render_pass_list.back()->quad_list.size());
-  cc::DrawQuad* draw_quad = frame.render_pass_list.back()->quad_list.back();
-  ASSERT_EQ(cc::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
+  viz::DrawQuad* draw_quad = frame.render_pass_list.back()->quad_list.back();
+  ASSERT_EQ(viz::DrawQuad::TEXTURE_CONTENT, draw_quad->material);
 
   const cc::TextureDrawQuad* texture_quad =
       cc::TextureDrawQuad::MaterialCast(draw_quad);
diff --git a/components/offline_pages/core/prefetch/BUILD.gn b/components/offline_pages/core/prefetch/BUILD.gn
index d231fb4..b934ede 100644
--- a/components/offline_pages/core/prefetch/BUILD.gn
+++ b/components/offline_pages/core/prefetch/BUILD.gn
@@ -171,6 +171,7 @@
     "metrics_finalization_task_unittest.cc",
     "page_bundle_update_task_unittest.cc",
     "prefetch_dispatcher_impl_unittest.cc",
+    "prefetch_download_flow_unittest.cc",
     "prefetch_downloader_impl_unittest.cc",
     "prefetch_gcm_app_handler_unittest.cc",
     "prefetch_item_unittest.cc",
@@ -183,6 +184,8 @@
     "store/prefetch_downloader_quota_unittest.cc",
     "store/prefetch_store_unittest.cc",
     "suggested_articles_observer_unittest.cc",
+    "test_download_client.cc",
+    "test_download_client.h",
   ]
 
   deps = [
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
index 59654f1..b78d016 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.cc
@@ -27,6 +27,7 @@
 #include "components/offline_pages/core/prefetch/page_bundle_update_task.h"
 #include "components/offline_pages/core/prefetch/prefetch_background_task_handler.h"
 #include "components/offline_pages/core/prefetch/prefetch_configuration.h"
+#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
 #include "components/offline_pages/core/prefetch/prefetch_gcm_handler.h"
 #include "components/offline_pages/core/prefetch/prefetch_importer.h"
 #include "components/offline_pages/core/prefetch/prefetch_network_request_factory.h"
@@ -137,6 +138,12 @@
       service_->GetPrefetchStore(),
       service_->GetPrefetchNetworkRequestFactory()));
 
+  // Notifies the downloader that the download cleanup can proceed when the
+  // download service is up. The prefetch service and download service are two
+  // separate services which can start up on their own. The download cleanup
+  // should only kick in when both services are ready.
+  service_->GetPrefetchDownloader()->CleanupDownloadsWhenReady();
+
   // This task should be last, because it is least important for correct
   // operation of the system, and because any reconciliation tasks might
   // generate more entries in the FINISHED state that the finalization task
@@ -148,10 +155,13 @@
 void PrefetchDispatcherImpl::QueueActionTasks() {
   service_->GetLogger()->RecordActivity("Dispatcher: Adding action tasks.");
 
-  std::unique_ptr<Task> download_archives_task =
-      base::MakeUnique<DownloadArchivesTask>(service_->GetPrefetchStore(),
-                                             service_->GetPrefetchDownloader());
-  task_queue_.AddTask(std::move(download_archives_task));
+  // Don't schedule any downloads if the download service can't be used at all.
+  if (!service_->GetPrefetchDownloader()->IsDownloadServiceUnavailable()) {
+    std::unique_ptr<Task> download_archives_task =
+        base::MakeUnique<DownloadArchivesTask>(
+            service_->GetPrefetchStore(), service_->GetPrefetchDownloader());
+    task_queue_.AddTask(std::move(download_archives_task));
+  }
 
   std::unique_ptr<Task> get_operation_task = base::MakeUnique<GetOperationTask>(
       service_->GetPrefetchStore(),
diff --git a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
index 9c4424b..770e836 100644
--- a/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h
@@ -5,7 +5,9 @@
 #ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DISPATCHER_IMPL_H_
 #define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_PREFETCH_DISPATCHER_IMPL_H_
 
+#include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
@@ -68,18 +70,18 @@
                         const std::string& operation_name,
                         const std::vector<RenderPageInfo>& pages);
 
-   // Adds the Reconcile tasks to the TaskQueue. These look for error/stuck
-   // processing conditions that happen as result of Chrome being evicted
-   // or network failures of certain kind. They are run on periodic wakeup
-   // (BeginBackgroundTask()). See PrefetchDispatcher interface
-   // declaration for Reconcile tasks definition.
-   void QueueReconcileTasks();
-   // Adds the Action tasks to the queue. See PrefetchDispatcher interface
-   // declaration for Action tasks definition.
-   // Action tasks can be added to the queue either in response to periodic
-   // wakeup (when BeginBackgroundTask() is called) or any time TaskQueue is
-   // becomes idle and any task called SchedulePipelineProcessing() before.
-   void QueueActionTasks();
+  // Adds the Reconcile tasks to the TaskQueue. These look for error/stuck
+  // processing conditions that happen as result of Chrome being evicted
+  // or network failures of certain kind. They are run on periodic wakeup
+  // (BeginBackgroundTask()). See PrefetchDispatcher interface
+  // declaration for Reconcile tasks definition.
+  void QueueReconcileTasks();
+  // Adds the Action tasks to the queue. See PrefetchDispatcher interface
+  // declaration for Action tasks definition.
+  // Action tasks can be added to the queue either in response to periodic
+  // wakeup (when BeginBackgroundTask() is called) or any time TaskQueue is
+  // becomes idle and any task called SchedulePipelineProcessing() before.
+  void QueueActionTasks();
 
   PrefetchService* service_;
   TaskQueue task_queue_;
diff --git a/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc b/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc
new file mode 100644
index 0000000..c35479f
--- /dev/null
+++ b/components/offline_pages/core/prefetch/prefetch_download_flow_unittest.cc
@@ -0,0 +1,208 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/prefetch/prefetch_downloader_impl.h"
+
+#include <utility>
+#include <vector>
+
+#include "base/test/scoped_feature_list.h"
+#include "components/download/internal/test/test_download_service.h"
+#include "components/offline_pages/core/offline_page_feature.h"
+#include "components/offline_pages/core/prefetch/prefetch_dispatcher_impl.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
+#include "components/offline_pages/core/prefetch/prefetch_service_test_taco.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_download_client.h"
+#include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+const version_info::Channel kTestChannel = version_info::Channel::UNKNOWN;
+const base::FilePath kTestFilePath(FILE_PATH_LITERAL("foo"));
+const int64_t kTestFileSize = 88888;
+
+class TestScopedBackgroundTask
+    : public offline_pages::PrefetchDispatcher::ScopedBackgroundTask {
+ public:
+  TestScopedBackgroundTask() = default;
+  ~TestScopedBackgroundTask() override = default;
+
+  void SetNeedsReschedule(bool reschedule, bool backoff) override {}
+};
+}  // namespace
+
+namespace offline_pages {
+
+// Tests the interaction between prefetch service and download service to
+// validate the whole prefetch download flow regardless which service is up
+// first.
+class PrefetchDownloadFlowTest : public TaskTestBase {
+ public:
+  PrefetchDownloadFlowTest() {
+    feature_list_.InitAndEnableFeature(kPrefetchingOfflinePagesFeature);
+  }
+
+  void SetUp() override {
+    TaskTestBase::SetUp();
+
+    prefetch_service_taco_.reset(new PrefetchServiceTestTaco);
+    auto downloader = base::MakeUnique<PrefetchDownloaderImpl>(
+        &download_service_, kTestChannel);
+    download_client_ = base::MakeUnique<TestDownloadClient>(downloader.get());
+    download_service_.set_client(download_client_.get());
+    prefetch_service_taco_->SetPrefetchDispatcher(
+        base::MakeUnique<PrefetchDispatcherImpl>());
+    prefetch_service_taco_->SetPrefetchStore(store_util()->ReleaseStore());
+    prefetch_service_taco_->SetPrefetchDownloader(std::move(downloader));
+    prefetch_service_taco_->CreatePrefetchService();
+  }
+
+  void TearDown() override {
+    prefetch_service_taco_.reset();
+    TaskTestBase::TearDown();
+  }
+
+  void SetDownloadServiceReady() {
+    SetDownloadServiceReadyWithParams(
+        std::set<std::string>(),
+        std::map<std::string, std::pair<base::FilePath, int64_t>>());
+  }
+
+  void SetDownloadServiceReadyWithParams(
+      const std::set<std::string>& outstanding_download_ids,
+      const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+          success_downloads) {
+    download_service_.SetIsReady(true);
+    prefetch_downloader()->OnDownloadServiceReady(
+        std::set<std::string>(),
+        std::map<std::string, std::pair<base::FilePath, int64_t>>());
+    RunUntilIdle();
+  }
+
+  TestPrefetchDispatcher* prefetch_dispatcher() const {
+    return static_cast<TestPrefetchDispatcher*>(
+        prefetch_service_taco_->prefetch_service()->GetPrefetchDispatcher());
+  }
+
+  PrefetchDownloader* prefetch_downloader() const {
+    return prefetch_service_taco_->prefetch_service()->GetPrefetchDownloader();
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list_;
+  download::test::TestDownloadService download_service_;
+  std::unique_ptr<TestDownloadClient> download_client_;
+  std::unique_ptr<PrefetchServiceTestTaco> prefetch_service_taco_;
+};
+
+TEST_F(PrefetchDownloadFlowTest, DownloadServiceReadyAfterPrefetchSystemReady) {
+  // Create an item ready for download.
+  PrefetchItem item =
+      item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+  item.archive_body_length = 100;
+  store_util()->InsertPrefetchItem(item);
+  RunUntilIdle();
+
+  // Start the prefetch processing pipeline.
+  prefetch_dispatcher()->BeginBackgroundTask(
+      base::MakeUnique<TestScopedBackgroundTask>());
+  RunUntilIdle();
+
+  // The item can still been scheduled for download though the download service
+  // is not ready.
+  std::unique_ptr<PrefetchItem> found_item =
+      store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(PrefetchItemState::DOWNLOADING, found_item->state);
+
+  // Now make the download service ready.
+  SetDownloadServiceReady();
+  RunUntilIdle();
+
+  // The item should finally transit to IMPORTING state.
+  found_item = store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(PrefetchItemState::IMPORTING, found_item->state);
+}
+
+TEST_F(PrefetchDownloadFlowTest,
+       DownloadServiceReadyBeforePrefetchSystemReady) {
+  // Download service is ready initially.
+  SetDownloadServiceReady();
+  RunUntilIdle();
+
+  // Create an item ready for download.
+  PrefetchItem item =
+      item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+  item.archive_body_length = 100;
+  store_util()->InsertPrefetchItem(item);
+  RunUntilIdle();
+
+  // Start the prefetch processing pipeline.
+  prefetch_dispatcher()->BeginBackgroundTask(
+      base::MakeUnique<TestScopedBackgroundTask>());
+  RunUntilIdle();
+
+  // The item should finally transit to IMPORTING state.
+  std::unique_ptr<PrefetchItem> found_item =
+      store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(PrefetchItemState::IMPORTING, found_item->state);
+}
+
+TEST_F(PrefetchDownloadFlowTest, DownloadServiceUnavailable) {
+  // Download service is unavailable.
+  EXPECT_FALSE(prefetch_downloader()->IsDownloadServiceUnavailable());
+  prefetch_downloader()->OnDownloadServiceUnavailable();
+  EXPECT_TRUE(prefetch_downloader()->IsDownloadServiceUnavailable());
+
+  // Create an item ready for download.
+  PrefetchItem item =
+      item_generator()->CreateItem(PrefetchItemState::RECEIVED_BUNDLE);
+  item.archive_body_length = 100;
+  store_util()->InsertPrefetchItem(item);
+  RunUntilIdle();
+
+  // Start the prefetch processing pipeline.
+  prefetch_dispatcher()->BeginBackgroundTask(
+      base::MakeUnique<TestScopedBackgroundTask>());
+  RunUntilIdle();
+
+  // The item should not be changed since download service can't be used.
+  std::unique_ptr<PrefetchItem> found_item =
+      store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(item, *found_item);
+}
+
+TEST_F(PrefetchDownloadFlowTest, DelayRunningDownloadCleanupTask) {
+  // Create an item in DOWNLOADING state.
+  PrefetchItem item =
+      item_generator()->CreateItem(PrefetchItemState::DOWNLOADING);
+  item.archive_body_length = 100;
+  store_util()->InsertPrefetchItem(item);
+  RunUntilIdle();
+
+  // Download service is ready.
+  std::set<std::string> outgoing_downloads;
+  std::map<std::string, std::pair<base::FilePath, int64_t>> success_downloads;
+  success_downloads.emplace(item.guid,
+                            std::make_pair(kTestFilePath, kTestFileSize));
+  SetDownloadServiceReadyWithParams(outgoing_downloads, success_downloads);
+
+  // The item should not be changed because the prefetch processing pipeline has
+  // not started yet and the download cleanup task will not be created.
+  std::unique_ptr<PrefetchItem> found_item =
+      store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(item, *found_item);
+
+  // Start the prefetch processing pipeline.
+  prefetch_dispatcher()->BeginBackgroundTask(
+      base::MakeUnique<TestScopedBackgroundTask>());
+  RunUntilIdle();
+
+  // The download cleanup task should be created and run. The item should
+  // finally transit to IMPORTING state.
+  found_item = store_util()->GetPrefetchItem(item.offline_id);
+  EXPECT_EQ(PrefetchItemState::IMPORTING, found_item->state);
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader.h b/components/offline_pages/core/prefetch/prefetch_downloader.h
index 76381a3..fa9dce15 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader.h
+++ b/components/offline_pages/core/prefetch/prefetch_downloader.h
@@ -23,15 +23,19 @@
 
   virtual void SetPrefetchService(PrefetchService* service) = 0;
 
+  // Returned true if the download service is not available and can't be used.
+  virtual bool IsDownloadServiceUnavailable() const = 0;
+
+  // Notifies that the download cleanup can be triggered immediately when the
+  // download service is ready. If the download service is ready before this
+  // method is called, the download cleanup should be delayed.
+  virtual void CleanupDownloadsWhenReady() = 0;
+
   // Starts to download an archive from |download_location|.
   virtual void StartDownload(const std::string& download_id,
                              const std::string& download_location) = 0;
 
-  // Cancels a previous scheduled download.
-  virtual void CancelDownload(const std::string& download_id) = 0;
-
-  // Called when the download service is initialized and can accept the
-  // downloads.
+  // Called when the download service is initialized.
   // |success_downloads| is a map with download_id as key and pair of file path
   // and file size as value.
   virtual void OnDownloadServiceReady(
@@ -43,9 +47,6 @@
   // used.
   virtual void OnDownloadServiceUnavailable() = 0;
 
-  // Called when the download service is tearing down.
-  virtual void OnDownloadServiceShutdown() = 0;
-
   // Called when a download is completed successfully. Note that the download
   // can be scheduled in previous sessions.
   virtual void OnDownloadSucceeded(const std::string& download_id,
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
index 403ce94c..ef67c4f 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl.cc
@@ -36,8 +36,6 @@
       channel_(channel),
       weak_ptr_factory_(this) {
   DCHECK(download_service);
-  service_started_ = download_service->GetStatus() ==
-                     download::DownloadService::ServiceStatus::READY;
 }
 
 PrefetchDownloaderImpl::PrefetchDownloaderImpl(version_info::Channel channel)
@@ -49,15 +47,23 @@
   prefetch_service_ = service;
 }
 
-void PrefetchDownloaderImpl::StartDownload(
-    const std::string& download_id,
-    const std::string& download_location) {
-  if (!service_started_) {
-    pending_downloads_.push_back(
-        std::make_pair(download_id, download_location));
+bool PrefetchDownloaderImpl::IsDownloadServiceUnavailable() const {
+  return download_service_status_ == DownloadServiceStatus::UNAVAILABLE;
+}
+
+void PrefetchDownloaderImpl::CleanupDownloadsWhenReady() {
+  // Trigger the download cleanup if the download service has already started.
+  if (download_service_status_ == DownloadServiceStatus::STARTED) {
+    CleanupDownloads(outstanding_download_ids_, success_downloads_);
     return;
   }
 
+  can_do_download_cleanup_ = true;
+}
+
+void PrefetchDownloaderImpl::StartDownload(
+    const std::string& download_id,
+    const std::string& download_location) {
   prefetch_service_->GetLogger()->RecordActivity(
       "Downloader: Start download of '" + download_location +
       "', download_id=" + download_id);
@@ -101,56 +107,42 @@
   params.scheduling_params.battery_requirements =
       download::SchedulingParams::BatteryRequirements::BATTERY_SENSITIVE;
   params.request_params.url = PrefetchDownloadURL(download_location, channel_);
+  // The download service can queue the download even if it is not fully up yet.
   download_service_->StartDownload(params);
 }
 
-void PrefetchDownloaderImpl::CancelDownload(const std::string& download_id) {
-  if (service_started_) {
-    download_service_->CancelDownload(download_id);
-    return;
-  }
-  for (auto iter = pending_downloads_.begin(); iter != pending_downloads_.end();
-       ++iter) {
-    if (iter->first == download_id) {
-      pending_downloads_.erase(iter);
-      return;
-    }
-  }
-  pending_cancellations_.push_back(download_id);
-}
-
 void PrefetchDownloaderImpl::OnDownloadServiceReady(
     const std::set<std::string>& outstanding_download_ids,
     const std::map<std::string, std::pair<base::FilePath, int64_t>>&
         success_downloads) {
+  DCHECK_EQ(DownloadServiceStatus::INITIALIZING, download_service_status_);
+  download_service_status_ = DownloadServiceStatus::STARTED;
+
   prefetch_service_->GetLogger()->RecordActivity("Downloader: Service ready.");
-  DCHECK_EQ(download::DownloadService::ServiceStatus::READY,
-            download_service_->GetStatus());
-  service_started_ = true;
 
-  PrefetchDispatcher* dispatcher = prefetch_service_->GetPrefetchDispatcher();
-  if (dispatcher)
-    dispatcher->CleanupDownloads(outstanding_download_ids, success_downloads);
+  // If the prefetch service has requested the download cleanup, do it now.
+  if (can_do_download_cleanup_) {
+    CleanupDownloads(outstanding_download_ids, success_downloads);
+    can_do_download_cleanup_ = false;
+    return;
+  }
 
-  for (const auto& entry : pending_downloads_)
-    StartDownload(entry.first, entry.second);
-  pending_downloads_.clear();
-
-  for (const auto& entry : pending_cancellations_)
-    download_service_->CancelDownload(entry);
-  pending_cancellations_.clear();
+  // Otherwise, cache the download cleanup data until told by the prefetch
+  // service.
+  outstanding_download_ids_ = outstanding_download_ids;
+  success_downloads_ = success_downloads;
 }
 
 void PrefetchDownloaderImpl::OnDownloadServiceUnavailable() {
+  DCHECK_EQ(DownloadServiceStatus::INITIALIZING, download_service_status_);
+  download_service_status_ = DownloadServiceStatus::UNAVAILABLE;
+
   prefetch_service_->GetLogger()->RecordActivity(
       "Downloader: Service unavailable.");
-  // TODO(jianli): Report UMA.
-}
 
-void PrefetchDownloaderImpl::OnDownloadServiceShutdown() {
-  prefetch_service_->GetLogger()->RecordActivity(
-      "Downloader: Service shutdown.");
-  service_started_ = false;
+  // The download service is unavailable to use for the whole lifetime of
+  // Chrome. PrefetchService can't schedule any downloads. Next time when Chrome
+  // restarts, the download service might be back to operational.
 }
 
 void PrefetchDownloaderImpl::OnDownloadSucceeded(
@@ -185,4 +177,13 @@
     OnDownloadFailed(download_id);
 }
 
+void PrefetchDownloaderImpl::CleanupDownloads(
+    const std::set<std::string>& outstanding_download_ids,
+    const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+        success_downloads) {
+  PrefetchDispatcher* dispatcher = prefetch_service_->GetPrefetchDispatcher();
+  if (dispatcher)
+    dispatcher->CleanupDownloads(outstanding_download_ids, success_downloads);
+}
+
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl.h b/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
index 7c6b5ae..dbb6651 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl.h
@@ -35,15 +35,15 @@
 
   // PrefetchDownloader implementation:
   void SetPrefetchService(PrefetchService* service) override;
+  bool IsDownloadServiceUnavailable() const override;
+  void CleanupDownloadsWhenReady() override;
   void StartDownload(const std::string& download_id,
                      const std::string& download_location) override;
-  void CancelDownload(const std::string& download_id) override;
   void OnDownloadServiceReady(
       const std::set<std::string>& outstanding_download_ids,
       const std::map<std::string, std::pair<base::FilePath, int64_t>>&
           success_downloads) override;
   void OnDownloadServiceUnavailable() override;
-  void OnDownloadServiceShutdown() override;
   void OnDownloadSucceeded(const std::string& download_id,
                            const base::FilePath& file_path,
                            int64_t file_size) override;
@@ -52,6 +52,16 @@
  private:
   friend class PrefetchServiceTestTaco;
 
+  enum class DownloadServiceStatus {
+    // The download service is booting up.
+    INITIALIZING,
+    // The download service is up and can take downloads.
+    STARTED,
+    // The download service is unavailable to use for the whole lifetime of
+    // Chrome.
+    UNAVAILABLE,
+  };
+
   // For test only.
   explicit PrefetchDownloaderImpl(version_info::Channel channel);
 
@@ -59,6 +69,11 @@
   void OnStartDownload(const std::string& download_id,
                        download::DownloadParams::StartResult result);
 
+  void CleanupDownloads(
+      const std::set<std::string>& outstanding_download_ids,
+      const std::map<std::string, std::pair<base::FilePath, int64_t>>&
+          success_downloads);
+
   // Unowned. It is valid until |this| instance is disposed.
   download::DownloadService* download_service_;
 
@@ -68,16 +83,14 @@
   version_info::Channel channel_;
 
   // Flag to indicate if the download service is ready to take downloads.
-  bool service_started_ = false;
+  DownloadServiceStatus download_service_status_ =
+      DownloadServiceStatus::INITIALIZING;
 
-  // TODO(jianli): Investigate making PrefetchService waits for DownloadService
-  // ready in order to avoid queueing.
-  // List of downloads pending to start after the download service starts. Each
-  // item is a pair of download id and download location.
-  std::vector<std::pair<std::string, std::string>> pending_downloads_;
-  // List of ids of downloads waiting to be cancelled after the download service
-  // starts.
-  std::vector<std::string> pending_cancellations_;
+  // Flag to indicate that the download cleanup can proceed.
+  bool can_do_download_cleanup_ = false;
+
+  std::set<std::string> outstanding_download_ids_;
+  std::map<std::string, std::pair<base::FilePath, int64_t>> success_downloads_;
 
   base::WeakPtrFactory<PrefetchDownloaderImpl> weak_ptr_factory_;
 
diff --git a/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc b/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
index 1eb2228..dcf36438 100644
--- a/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
+++ b/components/offline_pages/core/prefetch/prefetch_downloader_impl_unittest.cc
@@ -4,22 +4,15 @@
 
 #include "components/offline_pages/core/prefetch/prefetch_downloader_impl.h"
 
-#include <list>
-#include <utility>
 #include <vector>
 
-#include "base/bind.h"
-#include "base/test/test_simple_task_runner.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "components/download/internal/test/empty_client.h"
 #include "components/download/internal/test/test_download_service.h"
-#include "components/download/public/download_metadata.h"
-#include "components/download/public/service_config.h"
 #include "components/offline_pages/core/prefetch/prefetch_service.h"
 #include "components/offline_pages/core/prefetch/prefetch_service_test_taco.h"
+#include "components/offline_pages/core/prefetch/task_test_base.h"
+#include "components/offline_pages/core/prefetch/test_download_client.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
 #include "net/base/url_util.h"
-#include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -34,73 +27,35 @@
 
 namespace offline_pages {
 
-class TestDownloadClient : public download::test::EmptyClient {
+class PrefetchDownloaderImplTest : public TaskTestBase {
  public:
-  explicit TestDownloadClient(PrefetchDownloader* downloader)
-      : downloader_(downloader) {}
-
-  ~TestDownloadClient() override = default;
-
-  void OnDownloadFailed(const std::string& guid,
-                        download::Client::FailureReason reason) override {
-    downloader_->OnDownloadFailed(guid);
-  }
-
-  void OnDownloadSucceeded(
-      const std::string& guid,
-      const download::CompletionInfo& completion_info) override {
-    downloader_->OnDownloadSucceeded(guid, completion_info.path,
-                                     completion_info.bytes_downloaded);
-  }
-
- private:
-  PrefetchDownloader* downloader_;
-};
-
-class PrefetchDownloaderTest : public testing::Test {
- public:
-  PrefetchDownloaderTest()
-      : task_runner_(new base::TestSimpleTaskRunner),
-        task_runner_handle_(task_runner_) {}
+  PrefetchDownloaderImplTest() = default;
 
   void SetUp() override {
     prefetch_service_taco_.reset(new PrefetchServiceTestTaco);
-    dispatcher_ = new TestPrefetchDispatcher();
 
     auto downloader = base::MakeUnique<PrefetchDownloaderImpl>(
         &download_service_, kTestChannel);
     download_service_.SetFailedDownload(kFailedDownloadId, false);
+    download_service_.SetIsReady(true);
     download_client_ = base::MakeUnique<TestDownloadClient>(downloader.get());
     download_service_.set_client(download_client_.get());
-    prefetch_service_taco_->SetPrefetchDispatcher(
-        base::WrapUnique(dispatcher_));
     prefetch_service_taco_->SetPrefetchDownloader(std::move(downloader));
     prefetch_service_taco_->CreatePrefetchService();
+
+    prefetch_downloader()->OnDownloadServiceReady(
+        std::set<std::string>(),
+        std::map<std::string, std::pair<base::FilePath, int64_t>>());
   }
 
   void TearDown() override {
     prefetch_service_taco_.reset();
-    PumpLoop();
-  }
-
-  void SetDownloadServiceReady(bool ready) {
-    download_service_.set_is_ready(ready);
-    if (ready) {
-      GetPrefetchDownloader()->OnDownloadServiceReady(
-          std::set<std::string>(),
-          std::map<std::string, std::pair<base::FilePath, int64_t>>());
-    } else {
-      GetPrefetchDownloader()->OnDownloadServiceShutdown();
-    }
+    TaskTestBase::TearDown();
   }
 
   void StartDownload(const std::string& download_id,
                      const std::string& download_location) {
-    GetPrefetchDownloader()->StartDownload(download_id, download_location);
-  }
-
-  void CancelDownload(const std::string& download_id) {
-    GetPrefetchDownloader()->CancelDownload(download_id);
+    prefetch_downloader()->StartDownload(download_id, download_location);
   }
 
   base::Optional<download::DownloadParams> GetDownload(
@@ -108,27 +63,26 @@
     return download_service_.GetDownload(guid);
   }
 
-  void PumpLoop() { task_runner_->RunUntilIdle(); }
-
   const std::vector<PrefetchDownloadResult>& completed_downloads() const {
-    return dispatcher_->download_results;
+    return prefetch_dispatcher()->download_results;
   }
 
  private:
-  PrefetchDownloader* GetPrefetchDownloader() const {
+  PrefetchDownloader* prefetch_downloader() const {
     return prefetch_service_taco_->prefetch_service()->GetPrefetchDownloader();
   }
 
-  scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
-  base::ThreadTaskRunnerHandle task_runner_handle_;
+  TestPrefetchDispatcher* prefetch_dispatcher() const {
+    return static_cast<TestPrefetchDispatcher*>(
+        prefetch_service_taco_->prefetch_service()->GetPrefetchDispatcher());
+  }
+
   download::test::TestDownloadService download_service_;
   std::unique_ptr<TestDownloadClient> download_client_;
   std::unique_ptr<PrefetchServiceTestTaco> prefetch_service_taco_;
-  TestPrefetchDispatcher* dispatcher_;
 };
 
-TEST_F(PrefetchDownloaderTest, DownloadParams) {
-  SetDownloadServiceReady(true);
+TEST_F(PrefetchDownloaderImplTest, DownloadParams) {
   StartDownload(kDownloadId, kDownloadLocation);
   base::Optional<download::DownloadParams> params = GetDownload(kDownloadId);
   ASSERT_TRUE(params.has_value());
@@ -143,17 +97,13 @@
   std::string alt_value;
   EXPECT_TRUE(net::GetValueForKeyInQuery(download_url, "alt", &alt_value));
   EXPECT_EQ("media", alt_value);
-  PumpLoop();
+  RunUntilIdle();
 }
 
-TEST_F(PrefetchDownloaderTest, StartDownloadBeforeServiceReady) {
-  SetDownloadServiceReady(false);
+TEST_F(PrefetchDownloaderImplTest, DownloadSucceeded) {
   StartDownload(kDownloadId, kDownloadLocation);
   StartDownload(kDownloadId2, kDownloadLocation2);
-  PumpLoop();
-  ASSERT_EQ(0u, completed_downloads().size());
-  SetDownloadServiceReady(true);
-  PumpLoop();
+  RunUntilIdle();
   ASSERT_EQ(2u, completed_downloads().size());
   EXPECT_EQ(kDownloadId, completed_downloads()[0].download_id);
   EXPECT_TRUE(completed_downloads()[0].success);
@@ -161,60 +111,12 @@
   EXPECT_TRUE(completed_downloads()[1].success);
 }
 
-TEST_F(PrefetchDownloaderTest, StartDownloadAfterServiceReady) {
-  SetDownloadServiceReady(true);
-  StartDownload(kDownloadId, kDownloadLocation);
-  StartDownload(kDownloadId2, kDownloadLocation2);
-  PumpLoop();
-  ASSERT_EQ(2u, completed_downloads().size());
-  EXPECT_EQ(kDownloadId, completed_downloads()[0].download_id);
-  EXPECT_TRUE(completed_downloads()[0].success);
-  EXPECT_EQ(kDownloadId2, completed_downloads()[1].download_id);
-  EXPECT_TRUE(completed_downloads()[1].success);
-}
-
-TEST_F(PrefetchDownloaderTest, DownloadFailed) {
-  SetDownloadServiceReady(true);
+TEST_F(PrefetchDownloaderImplTest, DownloadFailed) {
   StartDownload(kFailedDownloadId, kDownloadLocation);
-  PumpLoop();
+  RunUntilIdle();
   ASSERT_EQ(1u, completed_downloads().size());
   EXPECT_EQ(kFailedDownloadId, completed_downloads()[0].download_id);
   EXPECT_FALSE(completed_downloads()[0].success);
 }
 
-TEST_F(PrefetchDownloaderTest, CancelPendingDownloadBeforeServiceReady) {
-  SetDownloadServiceReady(false);
-  StartDownload(kDownloadId, kDownloadLocation);
-  StartDownload(kDownloadId2, kDownloadLocation2);
-  PumpLoop();
-  ASSERT_EQ(0u, completed_downloads().size());
-  CancelDownload(kDownloadId);
-  SetDownloadServiceReady(true);
-  PumpLoop();
-  ASSERT_EQ(1u, completed_downloads().size());
-  EXPECT_EQ(kDownloadId2, completed_downloads()[0].download_id);
-  EXPECT_TRUE(completed_downloads()[0].success);
-}
-
-TEST_F(PrefetchDownloaderTest, CancelStartedDownloadBeforeServiceReady) {
-  SetDownloadServiceReady(true);
-  StartDownload(kDownloadId, kDownloadLocation);
-  SetDownloadServiceReady(false);
-  CancelDownload(kDownloadId);
-  SetDownloadServiceReady(true);
-  PumpLoop();
-  ASSERT_EQ(0u, completed_downloads().size());
-}
-
-TEST_F(PrefetchDownloaderTest, CancelDownloadAfterServiceReady) {
-  SetDownloadServiceReady(true);
-  StartDownload(kDownloadId, kDownloadLocation);
-  StartDownload(kDownloadId2, kDownloadLocation2);
-  CancelDownload(kDownloadId);
-  PumpLoop();
-  ASSERT_EQ(1u, completed_downloads().size());
-  EXPECT_EQ(kDownloadId2, completed_downloads()[0].download_id);
-  EXPECT_TRUE(completed_downloads()[0].success);
-}
-
 }  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
index e57deff..6e6ef2f 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
+++ b/components/offline_pages/core/prefetch/prefetch_service_test_taco.cc
@@ -19,7 +19,6 @@
 #include "components/offline_pages/core/prefetch/prefetch_importer.h"
 #include "components/offline_pages/core/prefetch/prefetch_service_impl.h"
 #include "components/offline_pages/core/prefetch/store/prefetch_store.h"
-#include "components/offline_pages/core/prefetch/store/prefetch_store_test_util.h"
 #include "components/offline_pages/core/prefetch/suggested_articles_observer.h"
 #include "components/offline_pages/core/prefetch/test_offline_metrics_collector.h"
 #include "components/offline_pages/core/prefetch/test_prefetch_dispatcher.h"
@@ -66,7 +65,7 @@
   gcm_handler_ = base::MakeUnique<TestPrefetchGCMHandler>();
   network_request_factory_ =
       base::MakeUnique<TestPrefetchNetworkRequestFactory>();
-  prefetch_store_sql_ =
+  prefetch_store_ =
       base::MakeUnique<PrefetchStore>(base::ThreadTaskRunnerHandle::Get());
   suggested_articles_observer_ = base::MakeUnique<SuggestedArticlesObserver>();
   prefetch_downloader_ =
@@ -106,10 +105,10 @@
   network_request_factory_ = std::move(network_request_factory);
 }
 
-void PrefetchServiceTestTaco::SetPrefetchStoreSql(
-    std::unique_ptr<PrefetchStore> prefetch_store_sql) {
+void PrefetchServiceTestTaco::SetPrefetchStore(
+    std::unique_ptr<PrefetchStore> prefetch_store) {
   CHECK(!prefetch_service_);
-  prefetch_store_sql_ = std::move(prefetch_store_sql);
+  prefetch_store_ = std::move(prefetch_store);
 }
 
 void PrefetchServiceTestTaco::SetSuggestedArticlesObserver(
@@ -146,13 +145,13 @@
 
 void PrefetchServiceTestTaco::CreatePrefetchService() {
   CHECK(metrics_collector_ && dispatcher_ && gcm_handler_ &&
-        network_request_factory_ && prefetch_store_sql_ &&
+        network_request_factory_ && prefetch_store_ &&
         suggested_articles_observer_ && prefetch_downloader_);
 
   prefetch_service_ = base::MakeUnique<PrefetchServiceImpl>(
       std::move(metrics_collector_), std::move(dispatcher_),
       std::move(gcm_handler_), std::move(network_request_factory_),
-      std::move(prefetch_store_sql_), std::move(suggested_articles_observer_),
+      std::move(prefetch_store_), std::move(suggested_articles_observer_),
       std::move(prefetch_downloader_), std::move(prefetch_importer_),
       std::move(prefetch_background_task_handler_),
       std::move(prefetch_configuration_));
diff --git a/components/offline_pages/core/prefetch/prefetch_service_test_taco.h b/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
index 21798a2d6..61ac721 100644
--- a/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
+++ b/components/offline_pages/core/prefetch/prefetch_service_test_taco.h
@@ -47,7 +47,7 @@
   // Default type: TestNetworkRequestFactory.
   void SetPrefetchNetworkRequestFactory(
       std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory);
-  void SetPrefetchStoreSql(std::unique_ptr<PrefetchStore> prefetch_store_sql);
+  void SetPrefetchStore(std::unique_ptr<PrefetchStore> prefetch_store_sql);
   // Defaults to SuggestedArticlesObserver.  Initializes the testing suggestions
   // by default, so no ContentSuggestionsService is required..
   void SetSuggestedArticlesObserver(
@@ -81,7 +81,7 @@
   std::unique_ptr<PrefetchDispatcher> dispatcher_;
   std::unique_ptr<PrefetchGCMHandler> gcm_handler_;
   std::unique_ptr<PrefetchNetworkRequestFactory> network_request_factory_;
-  std::unique_ptr<PrefetchStore> prefetch_store_sql_;
+  std::unique_ptr<PrefetchStore> prefetch_store_;
   std::unique_ptr<SuggestedArticlesObserver> suggested_articles_observer_;
   std::unique_ptr<PrefetchDownloader> prefetch_downloader_;
   std::unique_ptr<PrefetchImporter> prefetch_importer_;
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
index dd1fef8..6c15c5b0 100644
--- a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
+++ b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.cc
@@ -188,19 +188,22 @@
   if (!temp_directory_.CreateUniqueTempDir())
     DVLOG(1) << "temp_directory_ not created";
 
-  store_.reset(new PrefetchStore(task_runner_, temp_directory_.GetPath()));
+  owned_store_.reset(
+      new PrefetchStore(task_runner_, temp_directory_.GetPath()));
+  store_ = owned_store_.get();
 }
 
 void PrefetchStoreTestUtil::BuildStoreInMemory() {
-  store_.reset(new PrefetchStore(task_runner_));
+  owned_store_.reset(new PrefetchStore(task_runner_));
+  store_ = owned_store_.get();
 }
 
 std::unique_ptr<PrefetchStore> PrefetchStoreTestUtil::ReleaseStore() {
-  return std::move(store_);
+  return std::move(owned_store_);
 }
 
 void PrefetchStoreTestUtil::DeleteStore() {
-  store_.reset();
+  owned_store_.reset();
   if (temp_directory_.IsValid()) {
     if (!temp_directory_.Delete())
       DVLOG(1) << "temp_directory_ not created";
diff --git a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
index d0d137a..2e27a6e0 100644
--- a/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
+++ b/components/offline_pages/core/prefetch/store/prefetch_store_test_util.h
@@ -79,7 +79,7 @@
   // Causes the store to behave as if an initialization error occurred.
   void SimulateInitializationError();
 
-  PrefetchStore* store() { return store_.get(); }
+  PrefetchStore* store() { return store_; }
 
   base::SimpleTestClock* clock() { return &clock_; }
 
@@ -88,7 +88,9 @@
 
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   base::ScopedTempDir temp_directory_;
-  std::unique_ptr<PrefetchStore> store_;
+  // TODO(jianli): Refactor this class to avoid owning the store.
+  std::unique_ptr<PrefetchStore> owned_store_;
+  PrefetchStore* store_;
   base::SimpleTestClock clock_;
 
   DISALLOW_COPY_AND_ASSIGN(PrefetchStoreTestUtil);
diff --git a/components/offline_pages/core/prefetch/test_download_client.cc b/components/offline_pages/core/prefetch/test_download_client.cc
new file mode 100644
index 0000000..41c181e
--- /dev/null
+++ b/components/offline_pages/core/prefetch/test_download_client.cc
@@ -0,0 +1,27 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/offline_pages/core/prefetch/test_download_client.h"
+
+#include "components/offline_pages/core/prefetch/prefetch_downloader.h"
+
+namespace offline_pages {
+
+TestDownloadClient::TestDownloadClient(PrefetchDownloader* downloader)
+    : downloader_(downloader) {}
+
+void TestDownloadClient::OnDownloadFailed(
+    const std::string& guid,
+    download::Client::FailureReason reason) {
+  downloader_->OnDownloadFailed(guid);
+}
+
+void TestDownloadClient::OnDownloadSucceeded(
+    const std::string& guid,
+    const download::CompletionInfo& completion_info) {
+  downloader_->OnDownloadSucceeded(guid, completion_info.path,
+                                   completion_info.bytes_downloaded);
+}
+
+}  // namespace offline_pages
diff --git a/components/offline_pages/core/prefetch/test_download_client.h b/components/offline_pages/core/prefetch/test_download_client.h
new file mode 100644
index 0000000..70b2ead
--- /dev/null
+++ b/components/offline_pages/core/prefetch/test_download_client.h
@@ -0,0 +1,34 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_CLIENT_H_
+#define COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_CLIENT_H_
+
+#include "base/macros.h"
+#include "components/download/internal/test/empty_client.h"
+
+namespace offline_pages {
+
+class PrefetchDownloader;
+
+class TestDownloadClient : public download::test::EmptyClient {
+ public:
+  explicit TestDownloadClient(PrefetchDownloader* downloader);
+  ~TestDownloadClient() override = default;
+
+  void OnDownloadFailed(const std::string& guid,
+                        download::Client::FailureReason reason) override;
+  void OnDownloadSucceeded(
+      const std::string& guid,
+      const download::CompletionInfo& completion_info) override;
+
+ private:
+  PrefetchDownloader* downloader_;
+
+  DISALLOW_COPY_AND_ASSIGN(TestDownloadClient);
+};
+
+}  // namespace offline_pages
+
+#endif  // COMPONENTS_OFFLINE_PAGES_CORE_PREFETCH_TEST_DOWNLOAD_CLIENT_H_
diff --git a/components/offline_pages/core/prefetch/test_prefetch_downloader.cc b/components/offline_pages/core/prefetch/test_prefetch_downloader.cc
index 2ef9fd7..8e1025c 100644
--- a/components/offline_pages/core/prefetch/test_prefetch_downloader.cc
+++ b/components/offline_pages/core/prefetch/test_prefetch_downloader.cc
@@ -12,14 +12,18 @@
 
 void TestPrefetchDownloader::SetPrefetchService(PrefetchService* service) {}
 
+bool TestPrefetchDownloader::IsDownloadServiceUnavailable() const {
+  return false;
+}
+
+void TestPrefetchDownloader::CleanupDownloadsWhenReady() {}
+
 void TestPrefetchDownloader::StartDownload(
     const std::string& download_id,
     const std::string& download_location) {
   requested_downloads_[download_id] = download_location;
 }
 
-void TestPrefetchDownloader::CancelDownload(const std::string& download_id) {}
-
 void TestPrefetchDownloader::OnDownloadServiceReady(
     const std::set<std::string>& outstanding_download_ids,
     const std::map<std::string, std::pair<base::FilePath, int64_t>>&
@@ -27,8 +31,6 @@
 
 void TestPrefetchDownloader::OnDownloadServiceUnavailable() {}
 
-void TestPrefetchDownloader::OnDownloadServiceShutdown() {}
-
 void TestPrefetchDownloader::OnDownloadSucceeded(
     const std::string& download_id,
     const base::FilePath& file_path,
diff --git a/components/offline_pages/core/prefetch/test_prefetch_downloader.h b/components/offline_pages/core/prefetch/test_prefetch_downloader.h
index a288bde..85ba5981 100644
--- a/components/offline_pages/core/prefetch/test_prefetch_downloader.h
+++ b/components/offline_pages/core/prefetch/test_prefetch_downloader.h
@@ -20,15 +20,15 @@
   ~TestPrefetchDownloader() override;
 
   void SetPrefetchService(PrefetchService* service) override;
+  bool IsDownloadServiceUnavailable() const override;
+  void CleanupDownloadsWhenReady() override;
   void StartDownload(const std::string& download_id,
                      const std::string& download_location) override;
-  void CancelDownload(const std::string& download_id) override;
   void OnDownloadServiceReady(
       const std::set<std::string>& outstanding_download_ids,
       const std::map<std::string, std::pair<base::FilePath, int64_t>>&
           success_downloads) override;
   void OnDownloadServiceUnavailable() override;
-  void OnDownloadServiceShutdown() override;
   void OnDownloadSucceeded(const std::string& download_id,
                            const base::FilePath& file_path,
                            int64_t file_size) override;
diff --git a/components/security_interstitials_strings.grdp b/components/security_interstitials_strings.grdp
index 14fe3931..3063835 100644
--- a/components/security_interstitials_strings.grdp
+++ b/components/security_interstitials_strings.grdp
@@ -61,7 +61,7 @@
     &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; isn’t configured correctly. Uninstalling &quot;<ph name="SOFTWARE_NAME">$1<ex>Misconfigured Antivirus</ex></ph>&quot; usually fixes the problem. <ph name="FURTHER_EXPLANATION">$2<ex>Further explanation goes here.</ex></ph>
   </message>
   <message name="IDS_MITM_SOFTWARE_EXPLANATION" desc="Part of an extended description hidden behind an 'Advanced' button on an error page. A user visits a website, antivirus or firewall software interferes with their connection, and they are shown this error. Page title and additional description of the error are shown above. 'Antivirus software' is software that finds and deletes viruses on a user's computer. 'Firewall software' is software typically used on a company network that keeps unwanted people from accessing the network. 'Proxy software' is software on a network that blocks the user from viewing certain websites. Proxies may be used to keep school children from viewing inappropriate websites for example. 'Web-filtering software' is a synonym for proxy software, so it can be excluded in translation.">
-    Applications that can cause this error includes antivirus, firewall, and web-filtering or proxy software.
+    Applications that can cause this error include antivirus, firewall, and web-filtering or proxy software.
   </message>
 
   <!-- Clock errors -->
diff --git a/components/url_formatter/elide_url_unittest.cc b/components/url_formatter/elide_url_unittest.cc
index 58dbfb5c..419c01a 100644
--- a/components/url_formatter/elide_url_unittest.cc
+++ b/components/url_formatter/elide_url_unittest.cc
@@ -29,42 +29,167 @@
 };
 
 #if !defined(OS_ANDROID)
-void RunUrlTest(Testcase* testcases, size_t num_testcases) {
+void RunElisionTest(const std::vector<Testcase>& testcases) {
   const gfx::FontList font_list;
-  for (size_t i = 0; i < num_testcases; ++i) {
-    const GURL url(testcases[i].input);
+  for (const auto& testcase : testcases) {
+    SCOPED_TRACE("Eliding " + testcase.input);
+    const GURL url(testcase.input);
     const float available_width =
-        gfx::GetStringWidthF(base::UTF8ToUTF16(testcases[i].output), font_list);
-    EXPECT_EQ(base::UTF8ToUTF16(testcases[i].output),
+        gfx::GetStringWidthF(base::UTF8ToUTF16(testcase.output), font_list);
+    EXPECT_EQ(base::UTF8ToUTF16(testcase.output),
               url_formatter::ElideUrl(url, font_list, available_width));
   }
 }
 
+struct ProgressiveTestcase {
+  const std::string input;
+  const std::vector<std::string> output;
+};
+
+// Verify that one or more URLs passes through an explicit sequence of elided
+// strings as available space progressively decreases. This helps ensure that
+// transitional corner cases are handled properly. To be tolerant of
+// character-width variation across platforms, the test allows a limited number
+// of expected strings to be skipped mid-run.  The first and last expected
+// strings must be matched. Example:
+//
+// google.com/intl/en/.../ads/   <-- Must match.
+// google.com/intl/.../ads/
+// google.com/.../ads/
+// google.com/intl...   <- Can skip this, in case the 'l' does not fit.
+// google.com/int...
+// google.com/in...   <- Must match.
+//
+void RunProgressiveElisionTest(
+    const std::vector<ProgressiveTestcase>& testcases) {
+  const gfx::FontList font_list;
+  for (const auto& testcase : testcases) {
+    SCOPED_TRACE("Eliding " + testcase.input);
+    const GURL url(testcase.input);
+
+    // Occasionally, a parsed URL can grow in length before elision, such as
+    // when parsing a Windows file path with missing slashes.
+    ASSERT_FALSE(testcase.output.empty());
+    float width = std::max(
+        gfx::GetStringWidthF(base::UTF8ToUTF16(testcase.input), font_list),
+        gfx::GetStringWidthF(base::UTF8ToUTF16(testcase.output.front()),
+                             font_list));
+
+    // Ideally, this test would iterate through all available field widths on a
+    // per-pixel basis, but this is slow. Instead, compute the next input field
+    // width as slightly less than the previous elided string. This approach
+    // misses coverage in cases where a smaller available width generates a
+    // longer string than some other larger available width, but the tradeoff
+    // feels acceptable.
+    int mismatches = 0;
+    const int kMaxConsecutiveMismatches = 2;
+    for (size_t i = 0; i < testcase.output.size(); i++) {
+      const auto& expected = testcase.output[i];
+      base::string16 expected_utf16 = base::UTF8ToUTF16(expected);
+      base::string16 elided = url_formatter::ElideUrl(url, font_list, width);
+      if (expected_utf16 != elided) {
+        if (i > 0 && i < testcase.output.size() - 1 &&
+            mismatches < kMaxConsecutiveMismatches) {
+          mismatches++;
+          continue;
+        }
+        EXPECT_EQ(expected_utf16, elided);
+        break;
+      }
+      mismatches = 0;
+      float new_width = gfx::GetStringWidthF(elided, font_list);
+      // Elision rounds fractional available widths up.
+      EXPECT_LE(new_width, std::ceil(width)) << " at " << elided;
+      width = new_width - 1.0f;
+    }
+  }
+}
+
 // Test eliding of commonplace URLs.
 TEST(TextEliderTest, TestGeneralEliding) {
   const std::string kEllipsisStr(gfx::kEllipsis);
-  Testcase testcases[] = {
-      {"http://www.google.com/intl/en/ads/", "www.google.com/intl/en/ads/"},
-      {"http://www.google.com/intl/en/ads/", "www.google.com/intl/en/ads/"},
+  const std::vector<ProgressiveTestcase> progressive_testcases = {
+      // Elide a non-www URL (www URLs are handled differently). In this first
+      // case, elide down to nothing to test the terminal cases.
+      {"http://xyz.google.com/foo?bar",
+       {
+           /* clang-format off */
+           "xyz.google.com/foo?bar",
+           "xyz.google.com/foo?b" + kEllipsisStr,
+           "xyz.google.com/foo?" + kEllipsisStr,
+           "xyz.google.com/foo" + kEllipsisStr,
+           "xyz.google.com/fo" + kEllipsisStr,
+           "xyz.google.com/f" + kEllipsisStr,
+           kEllipsisStr + "google.com/foo" + kEllipsisStr,
+           kEllipsisStr + "google.com/fo" + kEllipsisStr,
+           kEllipsisStr + "google.com/f" + kEllipsisStr,
+           kEllipsisStr + "google.com/" + kEllipsisStr,
+           kEllipsisStr + "google.com" + kEllipsisStr,
+           kEllipsisStr + "google.co" + kEllipsisStr,
+           kEllipsisStr + "google.c" + kEllipsisStr,
+           kEllipsisStr + "google." + kEllipsisStr,
+           kEllipsisStr + "google" + kEllipsisStr,
+           kEllipsisStr + "googl" + kEllipsisStr,
+           kEllipsisStr + "goog" + kEllipsisStr,
+           kEllipsisStr + "goo" + kEllipsisStr,
+           kEllipsisStr + "go" + kEllipsisStr,
+           kEllipsisStr + "g" + kEllipsisStr,
+           kEllipsisStr + kEllipsisStr,
+           kEllipsisStr,
+           ""
+           /* clang-format on */
+       }},
+      // The trailing directory name is preserved
       {"http://www.google.com/intl/en/ads/",
-       "google.com/intl/" + kEllipsisStr + "/ads/"},
-      {"http://www.google.com/intl/en/ads/",
-       "google.com/" + kEllipsisStr + "/ads/"},
-      {"http://www.google.com/intl/en/ads/", "google.com/" + kEllipsisStr},
-      {"http://www.google.com/intl/en/ads/", "goog" + kEllipsisStr},
+       {
+           /* clang-format off */
+           "www.google.com/intl/en/ads/",
+           "google.com/intl/en/ads/",
+           "google.com/intl/" + kEllipsisStr + "/ads/",
+           "google.com/" + kEllipsisStr + "/ads/",
+           "google.com/" + kEllipsisStr + "/ad" + kEllipsisStr,
+           "google.com/" + kEllipsisStr + "/a" + kEllipsisStr,
+           "google.com/intl/" + kEllipsisStr,
+           "google.com/intl" + kEllipsisStr,
+           "google.com/int" + kEllipsisStr,
+           "google.com/in" + kEllipsisStr,
+           "google.com/i" + kEllipsisStr,
+           "google.com/" + kEllipsisStr,
+           "google.com" + kEllipsisStr,
+           "google.co" + kEllipsisStr,
+           "google.c" + kEllipsisStr,
+           "google." + kEllipsisStr,
+           "google" + kEllipsisStr,
+           "googl" + kEllipsisStr,
+           /* clang-format on */
+       }},
+      // Subdomain is completely elided if the last path element doesn't fit.
       {"https://subdomain.foo.com/bar/filename.html",
-       "https://subdomain.foo.com/bar/filename.html"},
-      {"https://subdomain.foo.com/bar/filename.html",
-       "subdomain.foo.com/bar/filename.html"},
-      {"https://subdomain.foo.com/bar/filename.html",
-       "subdomain.foo.com/" + kEllipsisStr + "/filename.html"},
-      {"http://subdomain.foo.com/bar/filename.html",
-       kEllipsisStr + "foo.com/" + kEllipsisStr + "/filename.html"},
-      {"http://www.google.com/intl/en/ads/?aLongQueryWhichIsNotRequired",
-       "www.google.com/intl/en/ads/?aLongQ" + kEllipsisStr},
+       {
+           /* clang-format off */
+           "https://subdomain.foo.com/bar/filename.html",
+           "subdomain.foo.com/bar/filename.html",
+           "subdomain.foo.com/" + kEllipsisStr + "/filename.html",
+           kEllipsisStr + "foo.com/bar/filename.html",
+           kEllipsisStr + "foo.com/" + kEllipsisStr + "/filename.html",
+           /* clang-format on */
+       }},
+      // Path eliding works when a query is present.
+      {"http://www.g.com/subdir/ads/?query",
+       {
+           /* clang-format off */
+           "www.g.com/subdir/ads/?query",
+           "www.g.com/subdir/ads/?que" + kEllipsisStr,
+           "www.g.com/subdir/ads/?qu" + kEllipsisStr,
+           "www.g.com/subdir/ads/?q" + kEllipsisStr,
+           "www.g.com/subdir/ads/?" + kEllipsisStr,
+           "www.g.com/subdir/ads/" + kEllipsisStr,
+           "www.g.com/subdir/ads" + kEllipsisStr,
+           "www.g.com/subdir/ad" + kEllipsisStr,
+           /* clang-format on */
+       }},
   };
-
-  RunUrlTest(testcases, arraysize(testcases));
+  RunProgressiveElisionTest(progressive_testcases);
 }
 
 // When there is very little space available, the elision code will shorten
@@ -107,44 +232,21 @@
             url_formatter::ElideUrl(url, font_list, available_width));
 
   // More space available - elide directories, partially elide filename.
-  Testcase testcases[] = {
+  const std::vector<Testcase> testcases = {
       {"http://battersbox.com/directory/foo/peter_paul_and_mary.html",
        "battersbox.com/" + kEllipsisStr + "/peter" + kEllipsisStr},
   };
-  RunUrlTest(testcases, arraysize(testcases));
+  RunElisionTest(testcases);
 }
 
 // Test eliding of empty strings, URLs with ports, passwords, queries, etc.
-TEST(TextEliderTest, TestMoreEliding) {
+TEST(TextEliderTest, TestElisionSpecialCases) {
 #if defined(OS_WIN)
   // Needed to bypass DCHECK in GetFallbackFont.
   base::MessageLoopForUI message_loop;
 #endif
   const std::string kEllipsisStr(gfx::kEllipsis);
-  Testcase testcases[] = {
-      // Eliding the same URL to various lengths.
-      {"http://xyz.google.com/foo?bar", "xyz.google.com/foo?bar"},
-      {"http://xyz.google.com/foo?bar", "xyz.google.com/foo?" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar", "xyz.google.com/foo" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar", "xyz.google.com/fo" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.com/fo" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.com/f" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.com/" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.com" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.co" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google.c" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar",
-       kEllipsisStr + "google." + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar", kEllipsisStr + "google" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar", kEllipsisStr + "googl" + kEllipsisStr},
-      {"http://xyz.google.com/foo?bar", kEllipsisStr + "g" + kEllipsisStr},
-
+  const std::vector<Testcase> testcases = {
       // URL with "www" subdomain (gets removed specially).
       {"http://www.google.com/foo?bar", "www.google.com/foo?bar"},
       {"http://www.google.com/foo?bar", "google.com/foo?bar"},
@@ -174,45 +276,65 @@
        "www/\xe4\xbd\xa0\xe5\xa5\xbd?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
 
       // Invalid unescaping for path. The ref will always be valid UTF-8. We
-      // don't
-      // bother to do too many edge cases, since these are handled by the
-      // escaper
-      // unittest.
+      // don't bother to do too many edge cases, since these are handled by the
+      // escaper unittest.
       {"http://www/%E4%A0%E5%A5%BD?q=%E4%BD%A0%E5%A5%BD#\xe4\xbd\xa0",
        "www/%E4%A0%E5%A5%BD?q=\xe4\xbd\xa0\xe5\xa5\xbd#\xe4\xbd\xa0"},
   };
 
-  RunUrlTest(testcases, arraysize(testcases));
+  RunElisionTest(testcases);
 }
 
 // Test eliding of file: URLs.
 TEST(TextEliderTest, TestFileURLEliding) {
   const std::string kEllipsisStr(gfx::kEllipsis);
-  Testcase testcases[] = {
+  const std::vector<ProgressiveTestcase> progressive_testcases = {
     {"file:///C:/path1/path2/path3/filename",
-     "file:///C:/path1/path2/path3/filename"},
-    {"file:///C:/path1/path2/path3/filename", "C:/path1/path2/path3/filename"},
+     {
+         /* clang-format off */
+         "file:///C:/path1/path2/path3/filename",
+         "C:/path1/path2/path3/filename",
+         "C:/path1/path2/" + kEllipsisStr + "/filename",
+         /* clang-format on */
+     }},
 // GURL parses "file:///C:path" differently on windows than it does on posix.
 #if defined(OS_WIN)
     {"file:///C:path1/path2/path3/filename",
-     "C:/path1/path2/" + kEllipsisStr + "/filename"},
-    {"file:///C:path1/path2/path3/filename",
-     "C:/path1/" + kEllipsisStr + "/filename"},
-    {"file:///C:path1/path2/path3/filename",
-     "C:/" + kEllipsisStr + "/filename"},
+     {
+         /* clang-format off */
+         "file:///C:/path1/path2/path3/filename",
+         "C:/path1/path2/path3/filename",
+         "C:/path1/path2/" + kEllipsisStr + "/filename",
+         "C:/path1/" + kEllipsisStr + "/filename",
+         "C:/" + kEllipsisStr + "/filename",
+         /* clang-format on */
+     }},
 #endif  // defined(OS_WIN)
-    {"file://filer/foo/bar/file", "filer/foo/bar/file"},
-    {"file://filer/foo/bar/file", "filer/foo/" + kEllipsisStr + "/file"},
-    {"file://filer/foo/bar/file", "filer/" + kEllipsisStr + "/file"},
-    {"file://filer/foo/", "file://filer/foo/"},
-    {"file://filer/foo/", "filer/foo/"},
-    {"file://filer/foo/", "filer" + kEllipsisStr},
-    // Eliding file URLs with nothing after the ':' shouldn't crash.
-    {"file:///aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:", "aaa" + kEllipsisStr},
-    {"file:///aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:/", "aaa" + kEllipsisStr},
+    {"file://filer/foo/bar/file",
+     {
+         /* clang-format off */
+         "file://filer/foo/bar/file",
+         "filer/foo/bar/file",
+         "filer/foo/" + kEllipsisStr + "/file",
+         "filer/" + kEllipsisStr + "/file",
+         "filer/foo" + kEllipsisStr,
+         "filer/fo" + kEllipsisStr,
+         "filer/f" + kEllipsisStr,
+         "filer/" + kEllipsisStr,
+         "filer" + kEllipsisStr,
+         "file" + kEllipsisStr,
+         /* clang-format on */
+     }},
   };
 
-  RunUrlTest(testcases, arraysize(testcases));
+  RunProgressiveElisionTest(progressive_testcases);
+
+  const std::vector<Testcase> testcases = {
+      // Eliding file URLs with nothing after the ':' shouldn't crash.
+      {"file:///aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:", "aaa" + kEllipsisStr},
+      {"file:///aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:/", "aaa" + kEllipsisStr},
+  };
+  RunElisionTest(testcases);
 }
 
 TEST(TextEliderTest, TestHostEliding) {
diff --git a/components/viz/client/BUILD.gn b/components/viz/client/BUILD.gn
index 96eb83e8..5eff4385 100644
--- a/components/viz/client/BUILD.gn
+++ b/components/viz/client/BUILD.gn
@@ -18,7 +18,6 @@
   public_deps = [
     "//base",
     "//cc",
-    "//cc/ipc:interfaces",
     "//components/viz/common",
     "//mojo/public/cpp/bindings",
     "//services/viz/public/interfaces",
diff --git a/components/viz/common/BUILD.gn b/components/viz/common/BUILD.gn
index 95ac2e7..1ae0618 100644
--- a/components/viz/common/BUILD.gn
+++ b/components/viz/common/BUILD.gn
@@ -60,6 +60,8 @@
     "quads/copy_output_request.h",
     "quads/copy_output_result.cc",
     "quads/copy_output_result.h",
+    "quads/draw_quad.cc",
+    "quads/draw_quad.h",
     "quads/release_callback.h",
     "quads/shared_bitmap.cc",
     "quads/shared_bitmap.h",
@@ -106,11 +108,11 @@
   ]
 
   deps = [
+    "//base",
+
     # TODO(staraz): cc/base was added because SharedQuadState includes
     # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
     "//cc/base",
-
-    "//base",
     "//gpu",
     "//gpu/command_buffer/client:gles2_implementation",
     "//gpu/command_buffer/client:gles2_interface",
diff --git a/cc/quads/draw_quad.cc b/components/viz/common/quads/draw_quad.cc
similarity index 61%
rename from cc/quads/draw_quad.cc
rename to components/viz/common/quads/draw_quad.cc
index 560f27f..01e58b1 100644
--- a/cc/quads/draw_quad.cc
+++ b/components/viz/common/quads/draw_quad.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/quads/draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 
 #include <stddef.h>
 
@@ -13,22 +13,21 @@
 #include "components/viz/common/traced_value.h"
 #include "ui/gfx/geometry/quad_f.h"
 
-namespace cc {
+namespace viz {
 
 DrawQuad::DrawQuad()
-    : material(INVALID), needs_blending(false), shared_quad_state(0) {
-}
+    : material(INVALID), needs_blending(false), shared_quad_state(0) {}
 
 DrawQuad::DrawQuad(const DrawQuad& other) = default;
 
-void DrawQuad::SetAll(const viz::SharedQuadState* shared_quad_state,
+void DrawQuad::SetAll(const SharedQuadState* shared_quad_state,
                       Material material,
                       const gfx::Rect& rect,
                       const gfx::Rect& visible_rect,
                       bool needs_blending) {
-  DCHECK(rect.Contains(visible_rect)) << "rect: " << rect.ToString()
-                                      << " visible_rect: "
-                                      << visible_rect.ToString();
+  DCHECK(rect.Contains(visible_rect))
+      << "rect: " << rect.ToString()
+      << " visible_rect: " << visible_rect.ToString();
 
   this->material = material;
   this->rect = rect;
@@ -40,33 +39,33 @@
   DCHECK(material != INVALID);
 }
 
-DrawQuad::~DrawQuad() {
-}
+DrawQuad::~DrawQuad() {}
 
 void DrawQuad::AsValueInto(base::trace_event::TracedValue* value) const {
   value->SetInteger("material", material);
-  viz::TracedValue::SetIDRef(shared_quad_state, value, "shared_state");
+  TracedValue::SetIDRef(shared_quad_state, value, "shared_state");
 
-  MathUtil::AddToTracedValue("content_space_rect", rect, value);
+  cc::MathUtil::AddToTracedValue("content_space_rect", rect, value);
 
   bool rect_is_clipped;
   gfx::QuadF rect_as_target_space_quad =
-      MathUtil::MapQuad(shared_quad_state->quad_to_target_transform,
-                        gfx::QuadF(gfx::RectF(rect)), &rect_is_clipped);
-  MathUtil::AddToTracedValue("rect_as_target_space_quad",
-                             rect_as_target_space_quad, value);
+      cc::MathUtil::MapQuad(shared_quad_state->quad_to_target_transform,
+                            gfx::QuadF(gfx::RectF(rect)), &rect_is_clipped);
+  cc::MathUtil::AddToTracedValue("rect_as_target_space_quad",
+                                 rect_as_target_space_quad, value);
 
   value->SetBoolean("rect_is_clipped", rect_is_clipped);
 
-  MathUtil::AddToTracedValue("content_space_visible_rect", visible_rect, value);
+  cc::MathUtil::AddToTracedValue("content_space_visible_rect", visible_rect,
+                                 value);
 
   bool visible_rect_is_clipped;
-  gfx::QuadF visible_rect_as_target_space_quad = MathUtil::MapQuad(
+  gfx::QuadF visible_rect_as_target_space_quad = cc::MathUtil::MapQuad(
       shared_quad_state->quad_to_target_transform,
       gfx::QuadF(gfx::RectF(visible_rect)), &visible_rect_is_clipped);
 
-  MathUtil::AddToTracedValue("visible_rect_as_target_space_quad",
-                             visible_rect_as_target_space_quad, value);
+  cc::MathUtil::AddToTracedValue("visible_rect_as_target_space_quad",
+                                 visible_rect_as_target_space_quad, value);
 
   value->SetBoolean("visible_rect_is_clipped", visible_rect_is_clipped);
 
@@ -80,4 +79,4 @@
     ids[i] = 0;
 }
 
-}  // namespace cc
+}  // namespace viz
diff --git a/cc/quads/draw_quad.h b/components/viz/common/quads/draw_quad.h
similarity index 85%
rename from cc/quads/draw_quad.h
rename to components/viz/common/quads/draw_quad.h
index 81b956e9..4cbe49f 100644
--- a/cc/quads/draw_quad.h
+++ b/components/viz/common/quads/draw_quad.h
@@ -2,23 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_QUADS_DRAW_QUAD_H_
-#define CC_QUADS_DRAW_QUAD_H_
+#ifndef COMPONENTS_VIZ_COMMON_QUADS_DRAW_QUAD_H_
+#define COMPONENTS_VIZ_COMMON_QUADS_DRAW_QUAD_H_
 
 #include <stddef.h>
 
 #include "base/callback.h"
-#include "cc/cc_export.h"
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "components/viz/common/resources/resource_id.h"
+#include "components/viz/common/viz_common_export.h"
 
 namespace base {
 namespace trace_event {
 class TracedValue;
 }
-}
+}  // namespace base
 
-namespace cc {
+namespace viz {
 
 // DrawQuad is a bag of data used for drawing a quad. Because different
 // materials need different bits of per-quad data to render, classes that derive
@@ -31,7 +31,7 @@
 // for most other layers). There is also the "target space", which is the space,
 // in "physical" pixels, of the render target where the quads is drawn. The
 // quad's transform maps the content space to the target space.
-class CC_EXPORT DrawQuad {
+class VIZ_COMMON_EXPORT DrawQuad {
  public:
   enum Material {
     INVALID,
@@ -68,7 +68,7 @@
   // Stores state common to a large bundle of quads; kept separate for memory
   // efficiency. There is special treatment to reconstruct these pointers
   // during serialization.
-  const viz::SharedQuadState* shared_quad_state;
+  const SharedQuadState* shared_quad_state;
 
   bool IsDebugQuad() const { return material == DEBUG_BORDER; }
 
@@ -104,24 +104,24 @@
 
   void AsValueInto(base::trace_event::TracedValue* value) const;
 
-  struct CC_EXPORT Resources {
+  struct VIZ_COMMON_EXPORT Resources {
     enum : size_t { kMaxResourceIdCount = 4 };
     Resources();
 
-    viz::ResourceId* begin() { return ids; }
-    viz::ResourceId* end() {
+    ResourceId* begin() { return ids; }
+    ResourceId* end() {
       DCHECK_LE(count, kMaxResourceIdCount);
       return ids + count;
     }
 
-    const viz::ResourceId* begin() const { return ids; }
-    const viz::ResourceId* end() const {
+    const ResourceId* begin() const { return ids; }
+    const ResourceId* end() const {
       DCHECK_LE(count, kMaxResourceIdCount);
       return ids + count;
     }
 
     uint32_t count;
-    viz::ResourceId ids[kMaxResourceIdCount];
+    ResourceId ids[kMaxResourceIdCount];
   };
 
   Resources resources;
@@ -129,7 +129,7 @@
  protected:
   DrawQuad();
 
-  void SetAll(const viz::SharedQuadState* shared_quad_state,
+  void SetAll(const SharedQuadState* shared_quad_state,
               Material material,
               const gfx::Rect& rect,
               const gfx::Rect& visible_rect,
@@ -137,6 +137,6 @@
   virtual void ExtendValue(base::trace_event::TracedValue* value) const = 0;
 };
 
-}  // namespace cc
+}  // namespace viz
 
-#endif  // CC_QUADS_DRAW_QUAD_H_
+#endif  // COMPONENTS_VIZ_COMMON_QUADS_DRAW_QUAD_H_
diff --git a/components/viz/common/quads/texture_mailbox.h b/components/viz/common/quads/texture_mailbox.h
index 3c24f3b..08880df 100644
--- a/components/viz/common/quads/texture_mailbox.h
+++ b/components/viz/common/quads/texture_mailbox.h
@@ -18,13 +18,11 @@
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
 
-namespace cc {
+namespace viz {
+
 namespace mojom {
 class TextureMailboxDataView;
 }
-}  // namespace cc
-
-namespace viz {
 
 class SharedBitmap;
 
@@ -102,7 +100,7 @@
 #endif
 
  private:
-  friend struct mojo::StructTraits<cc::mojom::TextureMailboxDataView,
+  friend struct mojo::StructTraits<mojom::TextureMailboxDataView,
                                    TextureMailbox>;
 
   gpu::MailboxHolder mailbox_holder_;
diff --git a/components/viz/host/BUILD.gn b/components/viz/host/BUILD.gn
index ecc7742..7287aee 100644
--- a/components/viz/host/BUILD.gn
+++ b/components/viz/host/BUILD.gn
@@ -22,7 +22,6 @@
 
   deps = [
     "//base",
-    "//cc/ipc:interfaces",
     "//components/viz/common",
     "//gpu/ipc/client",
     "//gpu/ipc/common",
@@ -57,7 +56,6 @@
     ":host",
     "//base",
     "//base/test:test_support",
-    "//cc/ipc:interfaces",
     "//gpu/ipc/host",
     "//mojo/public/cpp/bindings",
     "//services/ui/gpu/interfaces",
diff --git a/components/viz/host/host_frame_sink_manager.cc b/components/viz/host/host_frame_sink_manager.cc
index 943ba99..952cd33 100644
--- a/components/viz/host/host_frame_sink_manager.cc
+++ b/components/viz/host/host_frame_sink_manager.cc
@@ -72,6 +72,12 @@
   display_hit_test_query_.erase(frame_sink_id);
 }
 
+void HostFrameSinkManager::SetFrameSinkDebugLabel(
+    const FrameSinkId& frame_sink_id,
+    const std::string& debug_label) {
+  frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id, debug_label);
+}
+
 void HostFrameSinkManager::CreateRootCompositorFrameSink(
     const FrameSinkId& frame_sink_id,
     gpu::SurfaceHandle surface_handle,
diff --git a/components/viz/host/host_frame_sink_manager.h b/components/viz/host/host_frame_sink_manager.h
index 3f15308..c5ae9ed3 100644
--- a/components/viz/host/host_frame_sink_manager.h
+++ b/components/viz/host/host_frame_sink_manager.h
@@ -77,6 +77,11 @@
   // message pipe to the client will be closed.
   void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
 
+  // |debug_label| is used when printing out the surface hierarchy so we know
+  // which clients are contributing which surfaces.
+  void SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
+                              const std::string& debug_label);
+
   // Creates a connection for a display root to viz. Provides the same
   // interfaces as CreateCompositorFramesink() plus the priviledged
   // DisplayPrivate interface. When no longer needed, call
diff --git a/components/viz/host/host_frame_sink_manager_unittests.cc b/components/viz/host/host_frame_sink_manager_unittests.cc
index 272a278..a385bc7 100644
--- a/components/viz/host/host_frame_sink_manager_unittests.cc
+++ b/components/viz/host/host_frame_sink_manager_unittests.cc
@@ -63,6 +63,9 @@
   // mojom::FrameSinkManager:
   MOCK_METHOD1(RegisterFrameSinkId, void(const FrameSinkId& frame_sink_id));
   MOCK_METHOD1(InvalidateFrameSinkId, void(const FrameSinkId& frame_sink_id));
+  MOCK_METHOD2(SetFrameSinkDebugLabel,
+               void(const FrameSinkId& frame_sink_id,
+                    const std::string& debug_label));
   // Work around for gmock not supporting move-only types.
   void CreateCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
diff --git a/components/viz/service/BUILD.gn b/components/viz/service/BUILD.gn
index 97d1aee..427276e0 100644
--- a/components/viz/service/BUILD.gn
+++ b/components/viz/service/BUILD.gn
@@ -124,7 +124,6 @@
     "//base",
     "//cc",
     "//cc/debug",
-    "//cc/ipc:interfaces",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/ipc:command_buffer",
     "//services/viz/privileged/interfaces/compositing",
diff --git a/components/viz/service/display/gl_renderer.cc b/components/viz/service/display/gl_renderer.cc
index c7d1295..7d44919 100644
--- a/components/viz/service/display/gl_renderer.cc
+++ b/components/viz/service/display/gl_renderer.cc
@@ -586,48 +586,48 @@
   num_triangles_drawn_ = 0;
 }
 
-void GLRenderer::DoDrawQuad(const cc::DrawQuad* quad,
+void GLRenderer::DoDrawQuad(const DrawQuad* quad,
                             const gfx::QuadF* clip_region) {
   DCHECK(quad->rect.Contains(quad->visible_rect));
-  if (quad->material != cc::DrawQuad::TEXTURE_CONTENT) {
+  if (quad->material != DrawQuad::TEXTURE_CONTENT) {
     FlushTextureQuadCache(SHARED_BINDING);
   }
 
   switch (quad->material) {
-    case cc::DrawQuad::INVALID:
+    case DrawQuad::INVALID:
       NOTREACHED();
       break;
-    case cc::DrawQuad::DEBUG_BORDER:
+    case DrawQuad::DEBUG_BORDER:
       DrawDebugBorderQuad(cc::DebugBorderDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::PICTURE_CONTENT:
       // PictureDrawQuad should only be used for resourceless software draws.
       NOTREACHED();
       break;
-    case cc::DrawQuad::RENDER_PASS:
+    case DrawQuad::RENDER_PASS:
       DrawRenderPassQuad(cc::RenderPassDrawQuad::MaterialCast(quad),
                          clip_region);
       break;
-    case cc::DrawQuad::SOLID_COLOR:
+    case DrawQuad::SOLID_COLOR:
       DrawSolidColorQuad(cc::SolidColorDrawQuad::MaterialCast(quad),
                          clip_region);
       break;
-    case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::STREAM_VIDEO_CONTENT:
       DrawStreamVideoQuad(cc::StreamVideoDrawQuad::MaterialCast(quad),
                           clip_region);
       break;
-    case cc::DrawQuad::SURFACE_CONTENT:
+    case DrawQuad::SURFACE_CONTENT:
       // Surface content should be fully resolved to other quad types before
       // reaching a direct renderer.
       NOTREACHED();
       break;
-    case cc::DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::TEXTURE_CONTENT:
       EnqueueTextureQuad(cc::TextureDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case cc::DrawQuad::TILED_CONTENT:
+    case DrawQuad::TILED_CONTENT:
       DrawTileQuad(cc::TileDrawQuad::MaterialCast(quad), clip_region);
       break;
-    case cc::DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::YUV_VIDEO_CONTENT:
       DrawYUVVideoQuad(cc::YUVVideoDrawQuad::MaterialCast(quad), clip_region);
       break;
   }
@@ -1024,7 +1024,7 @@
   if (!pass->copy_requests.empty())
     return nullptr;
 
-  const cc::DrawQuad* quad = *pass->quad_list.BackToFrontBegin();
+  const DrawQuad* quad = *pass->quad_list.BackToFrontBegin();
   // Hack: this could be supported by concatenating transforms, but
   // in practice if there is one quad, it is at the origin of the render pass
   // and has the same size as the pass.
@@ -1034,7 +1034,7 @@
   // The quad is expected to be the entire layer so that AA edges are correct.
   if (quad->shared_quad_state->quad_layer_rect != quad->rect)
     return nullptr;
-  if (quad->material != cc::DrawQuad::TILED_CONTENT)
+  if (quad->material != DrawQuad::TILED_CONTENT)
     return nullptr;
 
   // TODO(chrishtr): support could be added for opacity, but care needs
@@ -1506,7 +1506,7 @@
 namespace {
 // These functions determine if a quad, clipped by a clip_region contains
 // the entire {top|bottom|left|right} edge.
-bool is_top(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+bool is_top(const gfx::QuadF* clip_region, const DrawQuad* quad) {
   if (!quad->IsTopEdge())
     return false;
   if (!clip_region)
@@ -1516,7 +1516,7 @@
          std::abs(clip_region->p2().y()) < kAntiAliasingEpsilon;
 }
 
-bool is_bottom(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+bool is_bottom(const gfx::QuadF* clip_region, const DrawQuad* quad) {
   if (!quad->IsBottomEdge())
     return false;
   if (!clip_region)
@@ -1530,7 +1530,7 @@
              kAntiAliasingEpsilon;
 }
 
-bool is_left(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+bool is_left(const gfx::QuadF* clip_region, const DrawQuad* quad) {
   if (!quad->IsLeftEdge())
     return false;
   if (!clip_region)
@@ -1540,7 +1540,7 @@
          std::abs(clip_region->p4().x()) < kAntiAliasingEpsilon;
 }
 
-bool is_right(const gfx::QuadF* clip_region, const cc::DrawQuad* quad) {
+bool is_right(const gfx::QuadF* clip_region, const DrawQuad* quad) {
   if (!quad->IsRightEdge())
     return false;
   if (!clip_region)
@@ -1560,7 +1560,7 @@
     const gfx::Transform& device_transform,
     const gfx::QuadF& tile_quad,
     const gfx::QuadF* clip_region,
-    const cc::DrawQuad* quad) {
+    const DrawQuad* quad) {
   auto tile_rect = gfx::RectF(quad->visible_rect);
 
   gfx::PointF bottom_right = tile_quad.p3();
@@ -1675,7 +1675,7 @@
 // static
 void GLRenderer::SetupQuadForClippingAndAntialiasing(
     const gfx::Transform& device_transform,
-    const cc::DrawQuad* quad,
+    const DrawQuad* quad,
     const gfx::QuadF* aa_quad,
     const gfx::QuadF* clip_region,
     gfx::QuadF* local_quad,
@@ -2643,7 +2643,7 @@
   gl_->Uniform2fv(current_program_->quad_location(), 4, gl_quad);
 }
 
-void GLRenderer::SetShaderOpacity(const cc::DrawQuad* quad) {
+void GLRenderer::SetShaderOpacity(const DrawQuad* quad) {
   if (!current_program_ || current_program_->alpha_location() == -1)
     return;
   gl_->Uniform1f(current_program_->alpha_location(),
@@ -3364,7 +3364,7 @@
     DCHECK(!dc_layer_overlay.rpdq);
 
     int i = 0;
-    unsigned texture_ids[cc::DrawQuad::Resources::kMaxResourceIdCount] = {};
+    unsigned texture_ids[DrawQuad::Resources::kMaxResourceIdCount] = {};
     int ids_to_send = 0;
 
     for (const auto& contents_resource_id : dc_layer_overlay.resources) {
diff --git a/components/viz/service/display/gl_renderer.h b/components/viz/service/display/gl_renderer.h
index 4cd1b602..9ce190a 100644
--- a/components/viz/service/display/gl_renderer.h
+++ b/components/viz/service/display/gl_renderer.h
@@ -95,7 +95,7 @@
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
-  void DoDrawQuad(const class cc::DrawQuad*,
+  void DoDrawQuad(const class DrawQuad*,
                   const gfx::QuadF* draw_region) override;
   void BeginDrawingFrame() override;
   void FinishDrawingFrame() override;
@@ -117,7 +117,7 @@
   // inflated quad's edge data.
   static void SetupQuadForClippingAndAntialiasing(
       const gfx::Transform& device_transform,
-      const cc::DrawQuad* quad,
+      const DrawQuad* quad,
       const gfx::QuadF* device_layer_quad,
       const gfx::QuadF* clip_region,
       gfx::QuadF* local_quad,
@@ -210,7 +210,7 @@
                         const gfx::QuadF* clip_region);
   void DrawOverlayCandidateQuadBorder(float* gl_matrix);
 
-  void SetShaderOpacity(const cc::DrawQuad* quad);
+  void SetShaderOpacity(const DrawQuad* quad);
   void SetShaderQuadF(const gfx::QuadF& quad);
   void SetShaderMatrix(const gfx::Transform& transform);
   void SetShaderColor(SkColor color, float opacity);
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index 82a84093..09663abf 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -315,7 +315,7 @@
   return false;
 }
 
-void SkiaRenderer::DoDrawQuad(const cc::DrawQuad* quad,
+void SkiaRenderer::DoDrawQuad(const DrawQuad* quad,
                               const gfx::QuadF* draw_region) {
   if (!current_canvas_)
     return;
@@ -377,32 +377,32 @@
   }
 
   switch (quad->material) {
-    case cc::DrawQuad::DEBUG_BORDER:
+    case DrawQuad::DEBUG_BORDER:
       DrawDebugBorderQuad(cc::DebugBorderDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::PICTURE_CONTENT:
+    case DrawQuad::PICTURE_CONTENT:
       DrawPictureQuad(cc::PictureDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::RENDER_PASS:
+    case DrawQuad::RENDER_PASS:
       DrawRenderPassQuad(cc::RenderPassDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::SOLID_COLOR:
+    case DrawQuad::SOLID_COLOR:
       DrawSolidColorQuad(cc::SolidColorDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::TEXTURE_CONTENT:
+    case DrawQuad::TEXTURE_CONTENT:
       DrawTextureQuad(cc::TextureDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::TILED_CONTENT:
+    case DrawQuad::TILED_CONTENT:
       DrawTileQuad(cc::TileDrawQuad::MaterialCast(quad));
       break;
-    case cc::DrawQuad::SURFACE_CONTENT:
+    case DrawQuad::SURFACE_CONTENT:
       // Surface content should be fully resolved to other quad types before
       // reaching a direct renderer.
       NOTREACHED();
       break;
-    case cc::DrawQuad::INVALID:
-    case cc::DrawQuad::YUV_VIDEO_CONTENT:
-    case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+    case DrawQuad::INVALID:
+    case DrawQuad::YUV_VIDEO_CONTENT:
+    case DrawQuad::STREAM_VIDEO_CONTENT:
       DrawUnsupportedQuad(quad);
       NOTREACHED();
       break;
@@ -604,7 +604,7 @@
   current_canvas_->drawRect(dest_visible_rect, current_paint_);
 }
 
-void SkiaRenderer::DrawUnsupportedQuad(const cc::DrawQuad* quad) {
+void SkiaRenderer::DrawUnsupportedQuad(const DrawQuad* quad) {
   // TODO(weiliangc): Make sure unsupported quads work. (crbug.com/644851)
   NOTIMPLEMENTED();
 #ifdef NDEBUG
diff --git a/components/viz/service/display/skia_renderer.h b/components/viz/service/display/skia_renderer.h
index f4795aa..13b202b4 100644
--- a/components/viz/service/display/skia_renderer.h
+++ b/components/viz/service/display/skia_renderer.h
@@ -47,8 +47,7 @@
   void SetScissorTestRect(const gfx::Rect& scissor_rect) override;
   void PrepareSurfaceForPass(SurfaceInitializationMode initialization_mode,
                              const gfx::Rect& render_pass_scissor) override;
-  void DoDrawQuad(const cc::DrawQuad* quad,
-                  const gfx::QuadF* draw_region) override;
+  void DoDrawQuad(const DrawQuad* quad, const gfx::QuadF* draw_region) override;
   void BeginDrawingFrame() override;
   void FinishDrawingFrame() override;
   bool FlippedFramebuffer() const override;
@@ -71,7 +70,7 @@
   void DrawSolidColorQuad(const cc::SolidColorDrawQuad* quad);
   void DrawTextureQuad(const cc::TextureDrawQuad* quad);
   void DrawTileQuad(const cc::TileDrawQuad* quad);
-  void DrawUnsupportedQuad(const cc::DrawQuad* quad);
+  void DrawUnsupportedQuad(const DrawQuad* quad);
   bool ShouldApplyBackgroundFilters(
       const cc::RenderPassDrawQuad* quad,
       const cc::FilterOperations* background_filters) const;
diff --git a/components/viz/service/display/surface_aggregator.cc b/components/viz/service/display/surface_aggregator.cc
index c3819e4..de33e58 100644
--- a/components/viz/service/display/surface_aggregator.cc
+++ b/components/viz/service/display/surface_aggregator.cc
@@ -18,12 +18,12 @@
 #include "base/trace_event/trace_event.h"
 #include "cc/base/math_util.h"
 #include "cc/output/compositor_frame.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
 #include "cc/quads/solid_color_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
 #include "cc/quads/texture_draw_quad.h"
 #include "cc/resources/display_resource_provider.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/quads/shared_quad_state.h"
 #include "components/viz/service/frame_sinks/compositor_frame_sink_support.h"
 #include "components/viz/service/surfaces/surface.h"
@@ -460,14 +460,14 @@
 #endif
 
   for (auto* quad : source_quad_list) {
-    if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == DrawQuad::SURFACE_CONTENT) {
       const auto* surface_quad = cc::SurfaceDrawQuad::MaterialCast(quad);
       // HandleSurfaceQuad may add other shared quad state, so reset the
       // current data.
       last_copied_source_shared_quad_state = nullptr;
 
       // The primary SurfaceDrawQuad should have already dealt with the fallback
-      // cc::DrawQuad.
+      // DrawQuad.
       if (surface_quad->surface_draw_quad_type ==
           cc::SurfaceDrawQuadType::FALLBACK)
         continue;
@@ -495,8 +495,8 @@
           continue;
       }
 
-      cc::DrawQuad* dest_quad;
-      if (quad->material == cc::DrawQuad::RENDER_PASS) {
+      DrawQuad* dest_quad;
+      if (quad->material == DrawQuad::RENDER_PASS) {
         const auto* pass_quad = cc::RenderPassDrawQuad::MaterialCast(quad);
         cc::RenderPassId original_pass_id = pass_quad->render_pass_id;
         cc::RenderPassId remapped_pass_id =
@@ -510,7 +510,7 @@
 
         dest_quad = dest_pass->CopyFromAndAppendRenderPassDrawQuad(
             pass_quad, remapped_pass_id);
-      } else if (quad->material == cc::DrawQuad::TEXTURE_CONTENT) {
+      } else if (quad->material == DrawQuad::TEXTURE_CONTENT) {
         const auto* texture_quad = cc::TextureDrawQuad::MaterialCast(quad);
         if (texture_quad->secure_output_only &&
             (!output_is_secure_ || copy_request_passes_.count(dest_pass->id))) {
@@ -720,7 +720,7 @@
     bool in_moved_pixel_pass = has_pixel_moving_filter ||
                                !!moved_pixel_passes_.count(remapped_pass_id);
     for (auto* quad : render_pass->quad_list) {
-      if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+      if (quad->material == DrawQuad::SURFACE_CONTENT) {
         const auto* surface_quad = cc::SurfaceDrawQuad::MaterialCast(quad);
         gfx::Transform target_to_surface_transform(
             render_pass->transform_to_root_target,
@@ -728,7 +728,7 @@
         child_surfaces.emplace_back(surface_quad->surface_id,
                                     in_moved_pixel_pass, remapped_pass_id,
                                     target_to_surface_transform);
-      } else if (quad->material == cc::DrawQuad::RENDER_PASS) {
+      } else if (quad->material == DrawQuad::RENDER_PASS) {
         const auto* render_pass_quad =
             cc::RenderPassDrawQuad::MaterialCast(quad);
         if (in_moved_pixel_pass) {
diff --git a/components/viz/service/display/surface_aggregator.h b/components/viz/service/display/surface_aggregator.h
index 106a4faf..1d786d1 100644
--- a/components/viz/service/display/surface_aggregator.h
+++ b/components/viz/service/display/surface_aggregator.h
@@ -12,8 +12,8 @@
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/common/resources/transferable_resource.h"
 #include "components/viz/common/surfaces/surface_id.h"
 #include "components/viz/service/viz_service_export.h"
diff --git a/components/viz/service/display/surface_aggregator_unittest.cc b/components/viz/service/display/surface_aggregator_unittest.cc
index 7945154b3..e7dde136 100644
--- a/components/viz/service/display/surface_aggregator_unittest.cc
+++ b/components/viz/service/display/surface_aggregator_unittest.cc
@@ -85,7 +85,7 @@
   struct Quad {
     static Quad SolidColorQuad(SkColor color) {
       Quad quad;
-      quad.material = cc::DrawQuad::SOLID_COLOR;
+      quad.material = DrawQuad::SOLID_COLOR;
       quad.color = color;
       return quad;
     }
@@ -94,7 +94,7 @@
                             const SurfaceId& fallback_surface_id,
                             float opacity) {
       Quad quad;
-      quad.material = cc::DrawQuad::SURFACE_CONTENT;
+      quad.material = DrawQuad::SURFACE_CONTENT;
       quad.opacity = opacity;
       quad.primary_surface_id = primary_surface_id;
       quad.fallback_surface_id = fallback_surface_id;
@@ -103,24 +103,23 @@
 
     static Quad RenderPassQuad(int id) {
       Quad quad;
-      quad.material = cc::DrawQuad::RENDER_PASS;
+      quad.material = DrawQuad::RENDER_PASS;
       quad.render_pass_id = id;
       return quad;
     }
 
-    cc::DrawQuad::Material material;
-    // Set when material==cc::DrawQuad::SURFACE_CONTENT.
+    DrawQuad::Material material;
+    // Set when material==DrawQuad::SURFACE_CONTENT.
     SurfaceId primary_surface_id;
     SurfaceId fallback_surface_id;
     float opacity;
-    // Set when material==cc::DrawQuad::SOLID_COLOR.
+    // Set when material==DrawQuad::SOLID_COLOR.
     SkColor color;
-    // Set when material==cc::DrawQuad::RENDER_PASS.
+    // Set when material==DrawQuad::RENDER_PASS.
     cc::RenderPassId render_pass_id;
 
    private:
-    Quad()
-        : material(cc::DrawQuad::INVALID), opacity(1.f), color(SK_ColorWHITE) {}
+    Quad() : material(DrawQuad::INVALID), opacity(1.f), color(SK_ColorWHITE) {}
   };
 
   struct Pass {
@@ -136,14 +135,14 @@
 
   static void AddQuadInPass(cc::RenderPass* pass, Quad desc) {
     switch (desc.material) {
-      case cc::DrawQuad::SOLID_COLOR:
+      case DrawQuad::SOLID_COLOR:
         AddQuad(pass, gfx::Rect(0, 0, 5, 5), desc.color);
         break;
-      case cc::DrawQuad::SURFACE_CONTENT:
+      case DrawQuad::SURFACE_CONTENT:
         AddSurfaceQuad(pass, gfx::Size(5, 5), desc.opacity,
                        desc.primary_surface_id, desc.fallback_surface_id);
         break;
-      case cc::DrawQuad::RENDER_PASS:
+      case DrawQuad::RENDER_PASS:
         AddRenderPassQuad(pass, desc.render_pass_id);
         break;
       default:
@@ -168,10 +167,10 @@
   }
 
   static void TestQuadMatchesExpectations(Quad expected_quad,
-                                          const cc::DrawQuad* quad) {
+                                          const DrawQuad* quad) {
     switch (expected_quad.material) {
-      case cc::DrawQuad::SOLID_COLOR: {
-        ASSERT_EQ(cc::DrawQuad::SOLID_COLOR, quad->material);
+      case DrawQuad::SOLID_COLOR: {
+        ASSERT_EQ(DrawQuad::SOLID_COLOR, quad->material);
 
         const auto* solid_color_quad =
             cc::SolidColorDrawQuad::MaterialCast(quad);
@@ -179,8 +178,8 @@
         EXPECT_EQ(expected_quad.color, solid_color_quad->color);
         break;
       }
-      case cc::DrawQuad::RENDER_PASS: {
-        ASSERT_EQ(cc::DrawQuad::RENDER_PASS, quad->material);
+      case DrawQuad::RENDER_PASS: {
+        ASSERT_EQ(DrawQuad::RENDER_PASS, quad->material);
 
         const auto* render_pass_quad =
             cc::RenderPassDrawQuad::MaterialCast(quad);
@@ -975,7 +974,7 @@
 
     // This render pass pass quad will reference the first pass from the
     // embedded surface, which is the second pass in the aggregated frame.
-    ASSERT_EQ(cc::DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::RENDER_PASS,
               third_pass_quad_list.ElementAt(1)->material);
     const auto* third_pass_render_pass_draw_quad =
         cc::RenderPassDrawQuad::MaterialCast(third_pass_quad_list.ElementAt(1));
@@ -997,7 +996,7 @@
 
     // The next quad will be a render pass quad referencing the second pass from
     // the embedded surface, which is the third pass in the aggregated frame.
-    ASSERT_EQ(cc::DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::RENDER_PASS,
               fourth_pass_quad_list.ElementAt(1)->material);
     const auto* fourth_pass_first_render_pass_draw_quad =
         cc::RenderPassDrawQuad::MaterialCast(
@@ -1007,7 +1006,7 @@
 
     // The last quad will be a render pass quad referencing the first pass from
     // the root surface, which is the first pass overall.
-    ASSERT_EQ(cc::DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::RENDER_PASS,
               fourth_pass_quad_list.ElementAt(2)->material);
     const auto* fourth_pass_second_render_pass_draw_quad =
         cc::RenderPassDrawQuad::MaterialCast(
@@ -1027,7 +1026,7 @@
     // The last quad in the last pass will reference the second pass from the
     // root surface, which after aggregating is the fourth pass in the overall
     // list.
-    ASSERT_EQ(cc::DrawQuad::RENDER_PASS,
+    ASSERT_EQ(DrawQuad::RENDER_PASS,
               fifth_pass_quad_list.ElementAt(1)->material);
     const auto* fifth_pass_render_pass_draw_quad =
         cc::RenderPassDrawQuad::MaterialCast(fifth_pass_quad_list.ElementAt(1));
@@ -1189,15 +1188,14 @@
   }
 
   // Make sure the render pass quads reference the remapped pass IDs.
-  cc::DrawQuad* render_pass_quads[] = {
-      aggregated_pass_list[1]->quad_list.front(),
-      aggregated_pass_list[2]->quad_list.front()};
-  ASSERT_EQ(render_pass_quads[0]->material, cc::DrawQuad::RENDER_PASS);
+  DrawQuad* render_pass_quads[] = {aggregated_pass_list[1]->quad_list.front(),
+                                   aggregated_pass_list[2]->quad_list.front()};
+  ASSERT_EQ(render_pass_quads[0]->material, DrawQuad::RENDER_PASS);
   EXPECT_EQ(actual_pass_ids[0],
             cc::RenderPassDrawQuad::MaterialCast(render_pass_quads[0])
                 ->render_pass_id);
 
-  ASSERT_EQ(render_pass_quads[1]->material, cc::DrawQuad::RENDER_PASS);
+  ASSERT_EQ(render_pass_quads[1]->material, DrawQuad::RENDER_PASS);
   EXPECT_EQ(actual_pass_ids[1],
             cc::RenderPassDrawQuad::MaterialCast(render_pass_quads[1])
                 ->render_pass_id);
@@ -2418,8 +2416,7 @@
 
   auto* render_pass = frame.render_pass_list.back().get();
 
-  EXPECT_EQ(cc::DrawQuad::TEXTURE_CONTENT,
-            render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT, render_pass->quad_list.back()->material);
 
   {
     auto pass = cc::RenderPass::Create();
@@ -2444,14 +2441,14 @@
   render_pass = frame.render_pass_list.front().get();
 
   // Parent has copy request, so texture should not be drawn.
-  EXPECT_EQ(cc::DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
 
   frame = aggregator_->Aggregate(surface2_id);
   EXPECT_EQ(1u, frame.render_pass_list.size());
   render_pass = frame.render_pass_list.front().get();
 
   // Copy request has been executed earlier, so texture should be drawn.
-  EXPECT_EQ(cc::DrawQuad::TEXTURE_CONTENT,
+  EXPECT_EQ(DrawQuad::TEXTURE_CONTENT,
             render_pass->quad_list.front()->material);
 
   aggregator_->set_output_is_secure(false);
@@ -2460,7 +2457,7 @@
   render_pass = frame.render_pass_list.back().get();
 
   // Output is insecure, so texture should be drawn.
-  EXPECT_EQ(cc::DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
+  EXPECT_EQ(DrawQuad::SOLID_COLOR, render_pass->quad_list.back()->material);
 
   support1->EvictCurrentSurface();
   support2->EvictCurrentSurface();
diff --git a/components/viz/service/display_embedder/buffer_queue.cc b/components/viz/service/display_embedder/buffer_queue.cc
index 8c59cf2..11cbf2d 100644
--- a/components/viz/service/display_embedder/buffer_queue.cc
+++ b/components/viz/service/display_embedder/buffer_queue.cc
@@ -89,7 +89,7 @@
 
 void BufferQueue::SwapBuffers(const gfx::Rect& damage) {
   if (damage.IsEmpty()) {
-    in_flight_surfaces_.push_back(nullptr);
+    in_flight_surfaces_.push_back(std::move(current_surface_));
     return;
   }
 
diff --git a/components/viz/service/display_embedder/buffer_queue_unittest.cc b/components/viz/service/display_embedder/buffer_queue_unittest.cc
index 2e7d71956..8d940ead 100644
--- a/components/viz/service/display_embedder/buffer_queue_unittest.cc
+++ b/components/viz/service/display_embedder/buffer_queue_unittest.cc
@@ -477,18 +477,35 @@
 }
 
 TEST_F(BufferQueueTest, CheckEmptySwap) {
-  // Check empty swap flow, in which the damage is empty.
+  // Check empty swap flow, in which the damage is empty and BindFramebuffer
+  // might not be called.
   EXPECT_EQ(0, CountBuffers());
   output_surface_->BindFramebuffer();
   EXPECT_EQ(1, CountBuffers());
   EXPECT_NE(0U, current_surface());
   EXPECT_FALSE(displayed_frame());
+
+  // This is the texture to scanout.
+  uint32_t texture_id = output_surface_->GetCurrentTextureId();
   SwapBuffers();
+  // Make sure we won't be drawing to the texture we just sent for scanout.
+  output_surface_->BindFramebuffer();
+  EXPECT_NE(texture_id, output_surface_->GetCurrentTextureId());
+
   EXPECT_EQ(1U, in_flight_surfaces().size());
-  EXPECT_EQ(nullptr, in_flight_surfaces().front());
+  output_surface_->PageFlipComplete();
+
+  // Test swapbuffers without calling BindFramebuffer. DirectRenderer skips
+  // BindFramebuffer if not necessary.
+  SwapBuffers();
+  SwapBuffers();
+  EXPECT_EQ(2U, in_flight_surfaces().size());
+
+  output_surface_->PageFlipComplete();
+  EXPECT_EQ(1U, in_flight_surfaces().size());
+
   output_surface_->PageFlipComplete();
   EXPECT_EQ(0U, in_flight_surfaces().size());
-  EXPECT_EQ(nullptr, displayed_frame());
 }
 
 TEST_F(BufferQueueTest, CheckCorrectBufferOrdering) {
diff --git a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
index 73b0b0d..b634016 100644
--- a/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
+++ b/components/viz/service/frame_sinks/compositor_frame_sink_support_unittest.cc
@@ -146,6 +146,8 @@
     manager_.SetLocalClient(&frame_sink_manager_client_);
     manager_.surface_manager()->AddObserver(&surface_observer_);
     manager_.RegisterFrameSinkId(kArbitraryFrameSinkId);
+    manager_.SetFrameSinkDebugLabel(kArbitraryFrameSinkId,
+                                    "kArbitraryFrameSinkId");
     support_ = CompositorFrameSinkSupport::Create(
         &fake_support_client_, &manager_, kArbitraryFrameSinkId, kIsRoot,
         kNeedsSyncPoints);
@@ -532,6 +534,8 @@
 
 TEST_F(CompositorFrameSinkSupportTest, AddDuringEviction) {
   manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
+  manager_.SetFrameSinkDebugLabel(kAnotherArbitraryFrameSinkId,
+                                  "kAnotherArbitraryFrameSinkId");
   test::MockCompositorFrameSinkSupportClient mock_client;
   auto support = CompositorFrameSinkSupport::Create(
       &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
@@ -552,6 +556,8 @@
 // Tests doing an EvictCurrentSurface before shutting down the factory.
 TEST_F(CompositorFrameSinkSupportTest, EvictCurrentSurface) {
   manager_.RegisterFrameSinkId(kAnotherArbitraryFrameSinkId);
+  manager_.SetFrameSinkDebugLabel(kAnotherArbitraryFrameSinkId,
+                                  "kAnotherArbitraryFrameSinkId");
   test::MockCompositorFrameSinkSupportClient mock_client;
   auto support = CompositorFrameSinkSupport::Create(
       &mock_client, &manager_, kAnotherArbitraryFrameSinkId, kIsRoot,
@@ -585,6 +591,7 @@
 TEST_F(CompositorFrameSinkSupportTest, EvictSurfaceWithTemporaryReference) {
   constexpr FrameSinkId parent_frame_sink_id(1234, 5678);
   manager_.RegisterFrameSinkId(parent_frame_sink_id);
+  manager_.SetFrameSinkDebugLabel(parent_frame_sink_id, "parent_frame_sink_id");
 
   const LocalSurfaceId local_surface_id(5, kArbitraryToken);
   const SurfaceId surface_id(support_->frame_sink_id(), local_surface_id);
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
index 6cc5b399..8e44f6d 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.cc
@@ -81,6 +81,12 @@
   surface_manager_.InvalidateFrameSinkId(frame_sink_id);
 }
 
+void FrameSinkManagerImpl::SetFrameSinkDebugLabel(
+    const FrameSinkId& frame_sink_id,
+    const std::string& debug_label) {
+  surface_manager_.SetFrameSinkDebugLabel(frame_sink_id, debug_label);
+}
+
 void FrameSinkManagerImpl::CreateRootCompositorFrameSink(
     const FrameSinkId& frame_sink_id,
     gpu::SurfaceHandle surface_handle,
diff --git a/components/viz/service/frame_sinks/frame_sink_manager_impl.h b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
index eac01a7..6086ad1 100644
--- a/components/viz/service/frame_sinks/frame_sink_manager_impl.h
+++ b/components/viz/service/frame_sinks/frame_sink_manager_impl.h
@@ -61,6 +61,8 @@
   // mojom::FrameSinkManager implementation:
   void RegisterFrameSinkId(const FrameSinkId& frame_sink_id) override;
   void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) override;
+  void SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
+                              const std::string& debug_label) override;
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
diff --git a/components/viz/service/surfaces/surface.cc b/components/viz/service/surfaces/surface.cc
index 429b115..04d3bd8 100644
--- a/components/viz/service/surfaces/surface.cc
+++ b/components/viz/service/surfaces/surface.cc
@@ -355,7 +355,7 @@
 
 void Surface::SatisfyDestructionDependencies(
     base::flat_set<SurfaceSequence>* sequences,
-    base::flat_set<FrameSinkId>* valid_frame_sink_ids) {
+    base::flat_map<FrameSinkId, std::string>* valid_frame_sink_ids) {
   base::EraseIf(destruction_dependencies_,
                 [sequences, valid_frame_sink_ids](SurfaceSequence seq) {
                   return (!!sequences->erase(seq) ||
diff --git a/components/viz/service/surfaces/surface.h b/components/viz/service/surfaces/surface.h
index 5544f2f..84534fc8 100644
--- a/components/viz/service/surfaces/surface.h
+++ b/components/viz/service/surfaces/surface.h
@@ -165,7 +165,7 @@
   // remove them from sequences.
   void SatisfyDestructionDependencies(
       base::flat_set<SurfaceSequence>* sequences,
-      base::flat_set<FrameSinkId>* valid_id_namespaces);
+      base::flat_map<FrameSinkId, std::string>* valid_id_namespaces);
   size_t GetDestructionDependencyCount() const {
     return destruction_dependencies_.size();
   }
diff --git a/components/viz/service/surfaces/surface_hittest.cc b/components/viz/service/surfaces/surface_hittest.cc
index e107af4..40c45b9 100644
--- a/components/viz/service/surfaces/surface_hittest.cc
+++ b/components/viz/service/surfaces/surface_hittest.cc
@@ -5,9 +5,9 @@
 #include "components/viz/service/surfaces/surface_hittest.h"
 
 #include "cc/output/compositor_frame.h"
-#include "cc/quads/draw_quad.h"
 #include "cc/quads/render_pass_draw_quad.h"
 #include "cc/quads/surface_draw_quad.h"
+#include "components/viz/common/quads/draw_quad.h"
 #include "components/viz/service/surfaces/surface.h"
 #include "components/viz/service/surfaces/surface_hittest_delegate.h"
 #include "components/viz/service/surfaces/surface_manager.h"
@@ -106,7 +106,7 @@
   gfx::Point point_in_render_pass_space(point_in_root_target);
   transform_from_root_target.TransformPoint(&point_in_render_pass_space);
 
-  for (const cc::DrawQuad* quad : render_pass->quad_list) {
+  for (const DrawQuad* quad : render_pass->quad_list) {
     gfx::Transform target_to_quad_transform;
     gfx::Point point_in_quad_space;
     if (!PointInQuad(quad, point_in_render_pass_space,
@@ -114,7 +114,7 @@
       continue;
     }
 
-    if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == DrawQuad::SURFACE_CONTENT) {
       // We've hit a cc::SurfaceDrawQuad, we need to recurse into this
       // Surface.
       const cc::SurfaceDrawQuad* surface_quad =
@@ -143,7 +143,7 @@
       continue;
     }
 
-    if (quad->material == cc::DrawQuad::RENDER_PASS) {
+    if (quad->material == DrawQuad::RENDER_PASS) {
       // We've hit a cc::RenderPassDrawQuad, we need to recurse into this
       // cc::RenderPass.
       const cc::RenderPassDrawQuad* render_quad =
@@ -201,8 +201,8 @@
     return false;
   }
 
-  for (const cc::DrawQuad* quad : render_pass->quad_list) {
-    if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+  for (const DrawQuad* quad : render_pass->quad_list) {
+    if (quad->material == DrawQuad::SURFACE_CONTENT) {
       gfx::Transform target_to_quad_transform;
       if (!quad->shared_quad_state->quad_to_target_transform.GetInverse(
               &target_to_quad_transform)) {
@@ -229,7 +229,7 @@
       continue;
     }
 
-    if (quad->material == cc::DrawQuad::RENDER_PASS) {
+    if (quad->material == DrawQuad::RENDER_PASS) {
       // We've hit a cc::RenderPassDrawQuad, we need to recurse into this
       // cc::RenderPass.
       const cc::RenderPassDrawQuad* render_quad =
@@ -272,7 +272,7 @@
   return nullptr;
 }
 
-bool SurfaceHittest::PointInQuad(const cc::DrawQuad* quad,
+bool SurfaceHittest::PointInQuad(const DrawQuad* quad,
                                  const gfx::Point& point_in_render_pass_space,
                                  gfx::Transform* target_to_quad_transform,
                                  gfx::Point* point_in_quad_space) {
diff --git a/components/viz/service/surfaces/surface_hittest.h b/components/viz/service/surfaces/surface_hittest.h
index 41b01c39..5f9bbbe 100644
--- a/components/viz/service/surfaces/surface_hittest.h
+++ b/components/viz/service/surfaces/surface_hittest.h
@@ -74,7 +74,7 @@
       const SurfaceId& surface_id,
       cc::RenderPassId render_pass_id);
 
-  bool PointInQuad(const cc::DrawQuad* quad,
+  bool PointInQuad(const DrawQuad* quad,
                    const gfx::Point& point_in_render_pass_space,
                    gfx::Transform* target_to_quad_transform,
                    gfx::Point* point_in_quad_space);
diff --git a/components/viz/service/surfaces/surface_manager.cc b/components/viz/service/surfaces/surface_manager.cc
index 2ef9a41..19504fa 100644
--- a/components/viz/service/surfaces/surface_manager.cc
+++ b/components/viz/service/surfaces/surface_manager.cc
@@ -158,12 +158,12 @@
 }
 
 void SurfaceManager::RegisterFrameSinkId(const FrameSinkId& frame_sink_id) {
-  bool inserted = valid_frame_sink_ids_.insert(frame_sink_id).second;
+  bool inserted = valid_frame_sink_labels_.emplace(frame_sink_id, "").second;
   DCHECK(inserted);
 }
 
 void SurfaceManager::InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) {
-  valid_frame_sink_ids_.erase(frame_sink_id);
+  valid_frame_sink_labels_.erase(frame_sink_id);
 
   // Remove any temporary references owned by |frame_sink_id|.
   std::vector<SurfaceId> temp_refs_to_clear;
@@ -179,6 +179,17 @@
   GarbageCollectSurfaces();
 }
 
+void SurfaceManager::SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
+                                            const std::string& debug_label) {
+#if DCHECK_IS_ON()
+  auto it = valid_frame_sink_labels_.find(frame_sink_id);
+  DCHECK(it != valid_frame_sink_labels_.end());
+  it->second = debug_label;
+#else
+  NOTREACHED();
+#endif
+}
+
 const SurfaceId& SurfaceManager::GetRootSurfaceId() const {
   return root_surface_id_;
 }
@@ -319,7 +330,7 @@
     const SurfaceId& surface_id = map_entry.first;
     Surface* surface = map_entry.second.get();
     surface->SatisfyDestructionDependencies(&satisfied_sequences_,
-                                            &valid_frame_sink_ids_);
+                                            &valid_frame_sink_labels_);
 
     if (!IsMarkedForDestruction(surface_id) ||
         surface->GetDestructionDependencyCount() > 0) {
@@ -556,6 +567,9 @@
   Surface* surface = GetSurfaceForId(surface_id);
   if (surface) {
     *str << surface->surface_id().ToString();
+    auto& label = valid_frame_sink_labels_[surface_id.frame_sink_id()];
+    if (!label.empty())
+      *str << " " << label;
     *str << (IsMarkedForDestruction(surface_id) ? " destroyed" : " live");
 
     if (surface->HasPendingFrame()) {
diff --git a/components/viz/service/surfaces/surface_manager.h b/components/viz/service/surfaces/surface_manager.h
index 2955b7ee..2936d08 100644
--- a/components/viz/service/surfaces/surface_manager.h
+++ b/components/viz/service/surfaces/surface_manager.h
@@ -132,6 +132,12 @@
   // possibly because a renderer process has crashed.
   void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id);
 
+  // Set |debug_label| of the |frame_sink_id|. |frame_sink_id| must exist in
+  // |valid_frame_sink_labels_| already when UpdateFrameSinkDebugLabel is
+  // called.
+  void SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
+                              const std::string& debug_label);
+
   // Register a relationship between two namespaces.  This relationship means
   // that surfaces from the child namespace will be displayed in the parent.
   // Children are allowed to use any begin frame source that their parent can
@@ -280,10 +286,10 @@
   // waited on.
   base::flat_set<SurfaceSequence> satisfied_sequences_;
 
-  // Set of valid FrameSinkIds. When a FrameSinkId is removed from
-  // this set, any remaining (surface) sequences with that FrameSinkId are
+  // Set of valid FrameSinkIds and their labels. When a FrameSinkId is removed
+  // from this set, any remaining (surface) sequences with that FrameSinkId are
   // considered satisfied.
-  base::flat_set<FrameSinkId> valid_frame_sink_ids_;
+  base::flat_map<FrameSinkId, std::string> valid_frame_sink_labels_;
 
   // Root SurfaceId that references display root surfaces. There is no Surface
   // with this id, it's for bookkeeping purposes only.
diff --git a/components/viz/test/test_frame_sink_manager.h b/components/viz/test/test_frame_sink_manager.h
index 0b7fb68..8a68190 100644
--- a/components/viz/test/test_frame_sink_manager.h
+++ b/components/viz/test/test_frame_sink_manager.h
@@ -22,6 +22,8 @@
   // mojom::FrameSinkManager:
   void RegisterFrameSinkId(const FrameSinkId& frame_sink_id) override {}
   void InvalidateFrameSinkId(const FrameSinkId& frame_sink_id) override {}
+  void SetFrameSinkDebugLabel(const FrameSinkId& frame_sink_id,
+                              const std::string& debug_label) override {}
   void CreateRootCompositorFrameSink(
       const FrameSinkId& frame_sink_id,
       gpu::SurfaceHandle surface_handle,
diff --git a/content/browser/download/download_item_impl.cc b/content/browser/download/download_item_impl.cc
index ce19b3a6..e26a147e 100644
--- a/content/browser/download/download_item_impl.cc
+++ b/content/browser/download/download_item_impl.cc
@@ -1426,6 +1426,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DVLOG(20) << __func__ << "() " << DebugString(true);
 
+  RecordDownloadCount(DETERMINE_DOWNLOAD_TARGET_COUNT);
   delegate_->DetermineDownloadTarget(
       this, base::Bind(&DownloadItemImpl::OnDownloadTargetDetermined,
                        weak_ptr_factory_.GetWeakPtr()));
@@ -1448,6 +1449,8 @@
             << DownloadInterruptReasonToString(interrupt_reason)
             << " this:" << DebugString(true);
 
+  RecordDownloadCount(DOWNLOAD_TARGET_DETERMINED_COUNT);
+
   if (IsCancellation(interrupt_reason) || target_path.empty()) {
     Cancel(true);
     return;
diff --git a/content/browser/download/download_stats.h b/content/browser/download/download_stats.h
index 7ad51f6..62ee585d0 100644
--- a/content/browser/download/download_stats.h
+++ b/content/browser/download/download_stats.h
@@ -114,6 +114,12 @@
   // bytes are received when resuming the download.
   NO_BYTES_RECEIVED_AFTER_CONTENT_LENGTH_MISMATCH_COUNT,
 
+  // Count of downloads that requested target determination.
+  DETERMINE_DOWNLOAD_TARGET_COUNT,
+
+  // Count of downloads that has target determination completed.
+  DOWNLOAD_TARGET_DETERMINED_COUNT,
+
   DOWNLOAD_COUNT_TYPES_LAST_ENTRY
 };
 
diff --git a/content/browser/renderer_host/compositor_impl_android.cc b/content/browser/renderer_host/compositor_impl_android.cc
index 1e05e6a..67204fb 100644
--- a/content/browser/renderer_host/compositor_impl_android.cc
+++ b/content/browser/renderer_host/compositor_impl_android.cc
@@ -477,6 +477,10 @@
       layer_tree_frame_sink_request_pending_(false),
       weak_factory_(this) {
   GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+  GetHostFrameSinkManager()->SetFrameSinkDebugLabel(frame_sink_id_,
+                                                    "CompositorImpl");
+#endif
   DCHECK(client);
   DCHECK(root_window);
   DCHECK(root_window->GetLayer() == nullptr);
diff --git a/content/browser/renderer_host/delegated_frame_host.cc b/content/browser/renderer_host/delegated_frame_host.cc
index c35725e9..fe71398d5 100644
--- a/content/browser/renderer_host/delegated_frame_host.cc
+++ b/content/browser/renderer_host/delegated_frame_host.cc
@@ -57,6 +57,10 @@
   viz::HostFrameSinkManager* host_frame_sink_manager =
       factory->GetContextFactoryPrivate()->GetHostFrameSinkManager();
   host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+  host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_,
+                                                  "DelegatedFrameHost");
+#endif
   CreateCompositorFrameSinkSupport();
 }
 
diff --git a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
index f6f54356..a60a65a 100644
--- a/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
+++ b/content/browser/renderer_host/offscreen_canvas_surface_impl.cc
@@ -32,6 +32,10 @@
       base::BindOnce(&OffscreenCanvasSurfaceImpl::OnSurfaceConnectionClosed,
                      base::Unretained(this)));
   host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+  host_frame_sink_manager_->SetFrameSinkDebugLabel(
+      frame_sink_id_, "OffscreenCanvasSurfaceImpl");
+#endif
 }
 
 OffscreenCanvasSurfaceImpl::~OffscreenCanvasSurfaceImpl() {
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 14c8c0f..0180d75 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -118,7 +118,6 @@
 #include "ui/accelerated_widget_mac/window_resize_helper_mac.h"
 #endif
 
-using base::Time;
 using base::TimeDelta;
 using base::TimeTicks;
 using blink::WebDragOperation;
diff --git a/content/browser/renderer_host/render_widget_host_view_child_frame.cc b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
index 8ce4d00..cf77affc 100644
--- a/content/browser/renderer_host/render_widget_host_view_child_frame.cc
+++ b/content/browser/renderer_host/render_widget_host_view_child_frame.cc
@@ -84,6 +84,10 @@
       weak_factory_(this) {
   if (!IsUsingMus()) {
     GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+    GetHostFrameSinkManager()->SetFrameSinkDebugLabel(
+        frame_sink_id_, "RenderWidgetHostViewChildFrame");
+#endif
     CreateCompositorFrameSinkSupport();
   }
 }
diff --git a/content/browser/resources/service_worker/OWNERS b/content/browser/resources/service_worker/OWNERS
index 00e8a780..299b6b92 100644
--- a/content/browser/resources/service_worker/OWNERS
+++ b/content/browser/resources/service_worker/OWNERS
@@ -1,9 +1,4 @@
-falken@chromium.org
-horo@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 # TEAM: worker-dev@chromium.org
 # COMPONENT: Blink>ServiceWorker
diff --git a/content/browser/service_worker/OWNERS b/content/browser/service_worker/OWNERS
index 00e8a780..4dc3f1d 100644
--- a/content/browser/service_worker/OWNERS
+++ b/content/browser/service_worker/OWNERS
@@ -1,5 +1,18 @@
+# Service Worker OWNERS
+#
+# This file also covers ownership of the following:
+#   //chrome/browser/chrome_service_worker_browsertest.cc
+#   //content/browser/resources/service_worker/
+#   //content/child/service_worker/
+#   //content/common/service_worker/
+#   //content/renderer/service_worker/
+#   //third_party/WebKit/public/web/modules/serviceworker/
+#   //third_party/WebKit/public/platform/modules/serviceworker/
+#   //third_party/WebKit/Source/modules/serviceworkers/
+
 falken@chromium.org
 horo@chromium.org
+kinuko@chromium.org
 mek@chromium.org
 michaeln@chromium.org
 nhiroki@chromium.org
diff --git a/content/child/blink_platform_impl.cc b/content/child/blink_platform_impl.cc
index 3d59b28..33d93604 100644
--- a/content/child/blink_platform_impl.cc
+++ b/content/child/blink_platform_impl.cc
@@ -559,7 +559,7 @@
     {"svg.css", IDR_UASTYLE_SVG_CSS, ui::SCALE_FACTOR_NONE, true},
     {"mathml.css", IDR_UASTYLE_MATHML_CSS, ui::SCALE_FACTOR_NONE, true},
     {"mediaControls.css", IDR_UASTYLE_MEDIA_CONTROLS_CSS, ui::SCALE_FACTOR_NONE,
-     false},
+     true},
     {"fullscreen.css", IDR_UASTYLE_FULLSCREEN_CSS, ui::SCALE_FACTOR_NONE, true},
     {"xhtmlmp.css", IDR_UASTYLE_XHTMLMP_CSS, ui::SCALE_FACTOR_NONE, true},
     {"viewportAndroid.css", IDR_UASTYLE_VIEWPORT_ANDROID_CSS,
diff --git a/content/child/service_worker/OWNERS b/content/child/service_worker/OWNERS
index 00e8a780..299b6b92 100644
--- a/content/child/service_worker/OWNERS
+++ b/content/child/service_worker/OWNERS
@@ -1,9 +1,4 @@
-falken@chromium.org
-horo@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 # TEAM: worker-dev@chromium.org
 # COMPONENT: Blink>ServiceWorker
diff --git a/content/common/service_worker/OWNERS b/content/common/service_worker/OWNERS
index c19de06..c334b174 100644
--- a/content/common/service_worker/OWNERS
+++ b/content/common/service_worker/OWNERS
@@ -1,9 +1,4 @@
-falken@chromium.org
-horo@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 per-file *_messages*.h=set noparent
 per-file *_messages*.h=file://ipc/SECURITY_OWNERS
diff --git a/content/public/common/media_stream_request.cc b/content/public/common/media_stream_request.cc
index cd181b9..47a1085f 100644
--- a/content/public/common/media_stream_request.cc
+++ b/content/public/common/media_stream_request.cc
@@ -78,16 +78,13 @@
 
 MediaStreamDevice::~MediaStreamDevice() {}
 
-bool MediaStreamDevice::IsEqual(const MediaStreamDevice& second) const {
-  const media::AudioParameters& input_second = second.input;
-  return type == second.type && name == second.name && id == second.id &&
-         input.sample_rate() == input_second.sample_rate() &&
-         input.channel_layout() == input_second.channel_layout();
-}
-
 bool MediaStreamDevice::IsSameDevice(
     const MediaStreamDevice& other_device) const {
-  return IsEqual(other_device) && session_id == other_device.session_id;
+  return type == other_device.type && name == other_device.name &&
+         id == other_device.id &&
+         input.sample_rate() == other_device.input.sample_rate() &&
+         input.channel_layout() == other_device.input.channel_layout() &&
+         session_id == other_device.session_id;
 }
 
 MediaStreamRequest::MediaStreamRequest(
diff --git a/content/public/common/media_stream_request.h b/content/public/common/media_stream_request.h
index 56a48d9..92f6339 100644
--- a/content/public/common/media_stream_request.h
+++ b/content/public/common/media_stream_request.h
@@ -106,7 +106,6 @@
 
   ~MediaStreamDevice();
 
-  bool IsEqual(const MediaStreamDevice& second) const;
   bool IsSameDevice(const MediaStreamDevice& other_device) const;
 
   // The device's type.
diff --git a/content/renderer/input/widget_input_handler_impl.cc b/content/renderer/input/widget_input_handler_impl.cc
index b731df44..916799e2 100644
--- a/content/renderer/input/widget_input_handler_impl.cc
+++ b/content/renderer/input/widget_input_handler_impl.cc
@@ -52,6 +52,15 @@
   return ime_text_spans;
 }
 
+void RunClosureIfNotSwappedOut(base::WeakPtr<RenderWidget> render_widget,
+                               base::OnceClosure closure) {
+  // Input messages must not be processed if the RenderWidget is in swapped out
+  // state.
+  if (!render_widget || render_widget->is_swapped_out())
+    return;
+  std::move(closure).Run();
+}
+
 }  // namespace
 
 WidgetInputHandlerImpl::WidgetInputHandlerImpl(
@@ -160,9 +169,10 @@
 
 void WidgetInputHandlerImpl::RunOnMainThread(base::OnceClosure closure) {
   if (input_event_queue_) {
-    input_event_queue_->QueueClosure(std::move(closure));
+    input_event_queue_->QueueClosure(base::BindOnce(
+        &RunClosureIfNotSwappedOut, render_widget_, std::move(closure)));
   } else {
-    std::move(closure).Run();
+    RunClosureIfNotSwappedOut(render_widget_, std::move(closure));
   }
 }
 
diff --git a/content/renderer/input/widget_input_handler_manager.cc b/content/renderer/input/widget_input_handler_manager.cc
index 9822f226..6d427339 100644
--- a/content/renderer/input/widget_input_handler_manager.cc
+++ b/content/renderer/input/widget_input_handler_manager.cc
@@ -285,7 +285,7 @@
     const ui::WebScopedInputEvent& event,
     const ui::LatencyInfo& latency,
     mojom::WidgetInputHandler::DispatchEventCallback callback) {
-  if (!render_widget_) {
+  if (!render_widget_ || render_widget_->is_swapped_out()) {
     std::move(callback).Run(InputEventAckSource::MAIN_THREAD, latency,
                             INPUT_EVENT_ACK_STATE_NOT_CONSUMED, base::nullopt,
                             base::nullopt);
diff --git a/content/renderer/service_worker/OWNERS b/content/renderer/service_worker/OWNERS
index 401d3a6..e370236aa 100644
--- a/content/renderer/service_worker/OWNERS
+++ b/content/renderer/service_worker/OWNERS
@@ -1,9 +1,4 @@
-falken@chromium.org
-horo@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 per-file *_type_converter*.*=set noparent
 per-file *_type_converter*.*=file://ipc/SECURITY_OWNERS
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 601cd19..99363bb 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -264,7 +264,6 @@
     "//cc:test_support",
     "//cc/blink",
     "//cc/ipc",
-    "//cc/ipc:interfaces",
     "//components/leveldb/public/interfaces",
     "//components/viz/host",
     "//components/viz/service",
diff --git a/content/test/gpu/generate_buildbot_json.py b/content/test/gpu/generate_buildbot_json.py
index 30634c7d..dec8b72 100755
--- a/content/test/gpu/generate_buildbot_json.py
+++ b/content/test/gpu/generate_buildbot_json.py
@@ -1417,6 +1417,13 @@
         'os_types': ['win', 'linux', 'mac', 'android'],
       },
     ],
+    'disabled_tester_configs': [
+      {
+        'names': [
+          'Linux Ozone (Intel)',
+        ],
+      },
+    ],
   },
   # The gles2_conform_tests are closed-source and deliberately only run
   # on the FYI waterfall and the optional tryservers.
diff --git a/content/test/test_render_view_host.cc b/content/test/test_render_view_host.cc
index 3919f426..fcc85da 100644
--- a/content/test/test_render_view_host.cc
+++ b/content/test/test_render_view_host.cc
@@ -76,6 +76,10 @@
   if (ImageTransportFactory::GetInstance()) {
     frame_sink_id_ = AllocateFrameSinkId();
     GetHostFrameSinkManager()->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+    GetHostFrameSinkManager()->SetFrameSinkDebugLabel(
+        frame_sink_id_, "TestRenderWidgetHostView");
+#endif
   }
 #endif
 
diff --git a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
index 67d21e9..120dee5f 100644
--- a/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
+++ b/extensions/browser/guest_view/extensions_guest_view_message_filter.cc
@@ -137,9 +137,7 @@
     const gfx::Size& new_size) {
   // We should have a GuestViewManager at this point. If we don't then the
   // embedder is misbehaving.
-  // TODO(mcnee): The renderer currently does this. Correct its behaviour
-  // so that we can enforce this.
-  auto* manager = GuestViewManager::FromBrowserContext(browser_context_);
+  auto* manager = GetGuestViewManagerOrKill();
   if (!manager)
     return;
 
diff --git a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
index f013f13..843c69e 100644
--- a/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
+++ b/extensions/renderer/guest_view/mime_handler_view/mime_handler_view_container.cc
@@ -195,6 +195,13 @@
   element_size_ = new_size;
 
   CreateMimeHandlerViewGuestIfNecessary();
+
+  // Don't try to resize a guest that hasn't been created yet. It is enough to
+  // initialise |element_size_| here and then we'll send that to the browser
+  // during guest creation.
+  if (!guest_created_)
+    return;
+
   render_frame()->Send(new ExtensionsGuestViewHostMsg_ResizeGuest(
       render_frame()->GetRoutingID(), element_instance_id(), new_size));
 }
diff --git a/mojo/public/tools/bindings/chromium_bindings_configuration.gni b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
index 976edf3..0f89593 100644
--- a/mojo/public/tools/bindings/chromium_bindings_configuration.gni
+++ b/mojo/public/tools/bindings/chromium_bindings_configuration.gni
@@ -4,7 +4,6 @@
 
 _typemap_imports = [
   "//ash/public/interfaces/typemaps.gni",
-  "//cc/ipc/typemaps.gni",
   "//chrome/common/extensions/typemaps.gni",
   "//chrome/common/importer/typemaps.gni",
   "//chrome/common/media_router/mojo/typemaps.gni",
diff --git a/net/android/java/src/org/chromium/net/X509Util.java b/net/android/java/src/org/chromium/net/X509Util.java
index 2bf8a19..117b35b 100644
--- a/net/android/java/src/org/chromium/net/X509Util.java
+++ b/net/android/java/src/org/chromium/net/X509Util.java
@@ -34,6 +34,7 @@
 import java.security.cert.CertificateFactory;
 import java.security.cert.CertificateNotYetValidException;
 import java.security.cert.X509Certificate;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
@@ -500,14 +501,21 @@
             return new AndroidCertVerifyResult(CertVerifyStatusAndroid.FAILED);
         }
 
-        X509Certificate[] serverCertificates = new X509Certificate[certChain.length];
+        List<X509Certificate> serverCertificatesList = new ArrayList<X509Certificate>();
         try {
-            for (int i = 0; i < certChain.length; ++i) {
-                serverCertificates[i] = createCertificateFromBytes(certChain[i]);
-            }
+            serverCertificatesList.add(createCertificateFromBytes(certChain[0]));
         } catch (CertificateException e) {
             return new AndroidCertVerifyResult(CertVerifyStatusAndroid.UNABLE_TO_PARSE);
         }
+        for (int i = 1; i < certChain.length; ++i) {
+            try {
+                serverCertificatesList.add(createCertificateFromBytes(certChain[i]));
+            } catch (CertificateException e) {
+                Log.w(TAG, "intermediate " + i + " failed parsing");
+            }
+        }
+        X509Certificate[] serverCertificates =
+                serverCertificatesList.toArray(new X509Certificate[serverCertificatesList.size()]);
 
         // Expired and not yet valid certificates would be rejected by the trust managers, but the
         // trust managers report all certificate errors using the general CertificateException. In
diff --git a/net/cert/cert_verify_proc_ios.cc b/net/cert/cert_verify_proc_ios.cc
index dd99c051..a93efff 100644
--- a/net/cert/cert_verify_proc_ios.cc
+++ b/net/cert/cert_verify_proc_ios.cc
@@ -251,11 +251,13 @@
     return NetErrorFromOSStatus(status);
 
   ScopedCFTypeRef<CFMutableArrayRef> cert_array(
-      x509_util::CreateSecCertificateArrayForX509Certificate(cert));
+      x509_util::CreateSecCertificateArrayForX509Certificate(
+          cert, x509_util::InvalidIntermediateBehavior::kIgnore));
   if (!cert_array) {
     verify_result->cert_status |= CERT_STATUS_INVALID;
     return ERR_CERT_INVALID;
   }
+
   ScopedCFTypeRef<SecTrustRef> trust_ref;
   SecTrustResultType trust_result = kSecTrustResultDeny;
   ScopedCFTypeRef<CFArrayRef> final_chain;
diff --git a/net/cert/cert_verify_proc_mac.cc b/net/cert/cert_verify_proc_mac.cc
index a279ebb..a345cfc 100644
--- a/net/cert/cert_verify_proc_mac.cc
+++ b/net/cert/cert_verify_proc_mac.cc
@@ -745,7 +745,8 @@
     }
 
     ScopedCFTypeRef<CFMutableArrayRef> cert_array(
-        x509_util::CreateSecCertificateArrayForX509Certificate(cert));
+        x509_util::CreateSecCertificateArrayForX509Certificate(
+            cert, x509_util::InvalidIntermediateBehavior::kIgnore));
     if (!cert_array) {
       verify_result->cert_status |= CERT_STATUS_INVALID;
       return ERR_CERT_INVALID;
diff --git a/net/cert/cert_verify_proc_nss.cc b/net/cert/cert_verify_proc_nss.cc
index 28b7fc7..20339e0 100644
--- a/net/cert/cert_verify_proc_nss.cc
+++ b/net/cert/cert_verify_proc_nss.cc
@@ -785,7 +785,8 @@
   // certificates for the intermediates is required for PKIXVerifyCert to find
   // them during chain building.
   ScopedCERTCertificateList input_chain =
-      x509_util::CreateCERTCertificateListFromX509Certificate(cert);
+      x509_util::CreateCERTCertificateListFromX509Certificate(
+          cert, x509_util::InvalidIntermediateBehavior::kIgnore);
   if (input_chain.empty()) {
     verify_result->cert_status |= CERT_STATUS_INVALID;
     return ERR_CERT_INVALID;
diff --git a/net/cert/cert_verify_proc_unittest.cc b/net/cert/cert_verify_proc_unittest.cc
index 6b8c875..57d3a28 100644
--- a/net/cert/cert_verify_proc_unittest.cc
+++ b/net/cert/cert_verify_proc_unittest.cc
@@ -491,8 +491,13 @@
 }
 
 // Tests the case where an intermediate certificate is accepted by
-// X509CertificateBytes, but has errors that should cause verification to fail.
-TEST_P(CertVerifyProcInternalTest, InvalidIntermediate) {
+// X509CertificateBytes, but has errors that should prevent using it during
+// verification.  The verification should succeed, since the intermediate
+// wasn't necessary.
+TEST_P(CertVerifyProcInternalTest, UnnecessaryInvalidIntermediate) {
+  ScopedTestRoot test_root(
+      ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem").get());
+
   base::FilePath certs_dir =
       GetTestNetDataDirectory().AppendASCII("parse_certificate_unittest");
   bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
@@ -515,8 +520,8 @@
   int error = Verify(cert_with_bad_intermediate.get(), "127.0.0.1", flags, NULL,
                      CertificateList(), &verify_result);
 
-  EXPECT_TRUE(verify_result.cert_status & CERT_STATUS_INVALID);
-  EXPECT_THAT(error, IsError(ERR_CERT_INVALID));
+  EXPECT_THAT(error, IsOk());
+  EXPECT_EQ(0u, verify_result.cert_status);
 }
 #endif  // BUILDFLAG(USE_BYTE_CERTS)
 
diff --git a/net/cert/cert_verify_proc_win.cc b/net/cert/cert_verify_proc_win.cc
index c94b58a..8318f8c9 100644
--- a/net/cert/cert_verify_proc_win.cc
+++ b/net/cert/cert_verify_proc_win.cc
@@ -854,7 +854,8 @@
   // CRLSet.
   ScopedThreadLocalCRLSet thread_local_crlset(crl_set);
 
-  ScopedPCCERT_CONTEXT cert_list = x509_util::CreateCertContextWithChain(cert);
+  ScopedPCCERT_CONTEXT cert_list = x509_util::CreateCertContextWithChain(
+      cert, x509_util::InvalidIntermediateBehavior::kIgnore);
   if (!cert_list) {
     verify_result->cert_status |= CERT_STATUS_INVALID;
     return ERR_CERT_INVALID;
diff --git a/net/cert/nss_cert_database.cc b/net/cert/nss_cert_database.cc
index 80f50ce2..51e497e 100644
--- a/net/cert/nss_cert_database.cc
+++ b/net/cert/nss_cert_database.cc
@@ -61,30 +61,6 @@
   DISALLOW_COPY_AND_ASSIGN(CertNotificationForwarder);
 };
 
-// TODO(mattm): remove this once crbug.com/671420 is done.
-ScopedCERTCertificateList CreateCERTCertificateListFromX509CertificateList(
-    const CertificateList& x509_certs) {
-  ScopedCERTCertificateList nss_certs;
-  for (const auto& x509_cert : x509_certs) {
-    ScopedCERTCertificate nss_cert =
-        x509_util::CreateCERTCertificateFromX509Certificate(x509_cert.get());
-    if (!nss_cert)
-      return {};
-    nss_certs.push_back(std::move(nss_cert));
-  }
-  return nss_certs;
-}
-
-// TODO(mattm): remove this once crbug.com/671420 is done.
-void ConvertOldCertsCallback(
-    const NSSCertDatabase::OldListCertsCallback& callback,
-    ScopedCERTCertificateList nss_certs) {
-  std::unique_ptr<CertificateList> x509_certs(new CertificateList());
-  *x509_certs =
-      x509_util::CreateX509CertificateListFromCERTCertificates(nss_certs);
-  callback.Run(std::move(x509_certs));
-}
-
 }  // namespace
 
 NSSCertDatabase::ImportCertFailure::ImportCertFailure(
@@ -118,10 +94,6 @@
 ScopedCERTCertificateList NSSCertDatabase::ListCertsSync() {
   return ListCertsImpl(crypto::ScopedPK11Slot());
 }
-void NSSCertDatabase::ListCertsSync(CertificateList* certs) {
-  *certs =
-      x509_util::CreateX509CertificateListFromCERTCertificates(ListCertsSync());
-}
 
 void NSSCertDatabase::ListCerts(const ListCertsCallback& callback) {
   base::PostTaskAndReplyWithResult(
@@ -131,10 +103,6 @@
       callback);
 }
 
-void NSSCertDatabase::ListCerts(const OldListCertsCallback& callback) {
-  ListCerts(base::Bind(&ConvertOldCertsCallback, callback));
-}
-
 void NSSCertDatabase::ListCertsInSlot(const ListCertsCallback& callback,
                                       PK11SlotInfo* slot) {
   DCHECK(slot);
@@ -146,11 +114,6 @@
       callback);
 }
 
-void NSSCertDatabase::ListCertsInSlot(const OldListCertsCallback& callback,
-                                      PK11SlotInfo* slot) {
-  ListCertsInSlot(base::Bind(&ConvertOldCertsCallback, callback), slot);
-}
-
 #if defined(OS_CHROMEOS)
 crypto::ScopedPK11Slot NSSCertDatabase::GetSystemSlot() const {
   return crypto::ScopedPK11Slot();
@@ -210,30 +173,6 @@
 
   return result;
 }
-int NSSCertDatabase::ImportFromPKCS12(PK11SlotInfo* slot_info,
-                                      const std::string& data,
-                                      const base::string16& password,
-                                      bool is_extractable,
-                                      CertificateList* imported_certs) {
-  ScopedCERTCertificateList nss_imported_certs;
-  int result = ImportFromPKCS12(slot_info, data, password, is_extractable,
-                                &nss_imported_certs);
-
-  if (imported_certs) {
-    *imported_certs = x509_util::CreateX509CertificateListFromCERTCertificates(
-        nss_imported_certs);
-  }
-  return result;
-}
-
-int NSSCertDatabase::ImportFromPKCS12(PK11SlotInfo* slot_info,
-                                      const std::string& data,
-                                      const base::string16& password,
-                                      bool is_extractable,
-                                      std::nullptr_t /* imported_certs */) {
-  return ImportFromPKCS12(slot_info, data, password, is_extractable,
-                          static_cast<ScopedCERTCertificateList*>(nullptr));
-}
 
 int NSSCertDatabase::ExportToPKCS12(const ScopedCERTCertificateList& certs,
                                     const base::string16& password,
@@ -241,16 +180,6 @@
   return psm::nsPKCS12Blob_Export(output, certs, password);
 }
 
-int NSSCertDatabase::ExportToPKCS12(const CertificateList& certs,
-                                    const base::string16& password,
-                                    std::string* output) const {
-  ScopedCERTCertificateList nss_certs =
-      CreateCERTCertificateListFromX509CertificateList(certs);
-  if (nss_certs.empty())
-    return 0;
-  return ExportToPKCS12(nss_certs, password, output);
-}
-
 CERTCertificate* NSSCertDatabase::FindRootInList(
     const ScopedCERTCertificateList& certificates) const {
   DCHECK_GT(certificates.size(), 0U);
@@ -272,29 +201,6 @@
   return cert0;
 }
 
-X509Certificate* NSSCertDatabase::FindRootInList(
-    const CertificateList& certificates) const {
-  DCHECK_GT(certificates.size(), 0U);
-
-  if (certificates.size() == 1)
-    return certificates[0].get();
-
-  X509Certificate* cert0 = certificates[0].get();
-  X509Certificate* cert1 = certificates[1].get();
-  X509Certificate* certn_2 = certificates[certificates.size() - 2].get();
-  X509Certificate* certn_1 = certificates[certificates.size() - 1].get();
-
-  if (CERT_CompareName(&cert1->os_cert_handle()->issuer,
-                       &cert0->os_cert_handle()->subject) == SECEqual)
-    return cert0;
-  if (CERT_CompareName(&certn_2->os_cert_handle()->issuer,
-                       &certn_1->os_cert_handle()->subject) == SECEqual)
-    return certn_1;
-
-  LOG(WARNING) << "certificate list is not a hierarchy";
-  return cert0;
-}
-
 int NSSCertDatabase::ImportUserCert(const std::string& data) {
   ScopedCERTCertificateList certificates =
       x509_util::CreateCERTCertificateListFromBytes(
@@ -319,14 +225,6 @@
   return result;
 }
 
-int NSSCertDatabase::ImportUserCert(X509Certificate* cert) {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  if (!nss_cert)
-    return ERR_CERT_INVALID;
-  return ImportUserCert(nss_cert.get());
-}
-
 bool NSSCertDatabase::ImportCACerts(
     const ScopedCERTCertificateList& certificates,
     TrustBits trust_bits,
@@ -341,16 +239,6 @@
   return success;
 }
 
-bool NSSCertDatabase::ImportCACerts(const CertificateList& certificates,
-                                    TrustBits trust_bits,
-                                    ImportCertFailureList* not_imported) {
-  ScopedCERTCertificateList nss_certs =
-      CreateCERTCertificateListFromX509CertificateList(certificates);
-  if (nss_certs.empty())
-    return false;
-  return ImportCACerts(nss_certs, trust_bits, not_imported);
-}
-
 bool NSSCertDatabase::ImportServerCert(
     const ScopedCERTCertificateList& certificates,
     TrustBits trust_bits,
@@ -360,16 +248,6 @@
                                not_imported);
 }
 
-bool NSSCertDatabase::ImportServerCert(const CertificateList& certificates,
-                                       TrustBits trust_bits,
-                                       ImportCertFailureList* not_imported) {
-  ScopedCERTCertificateList nss_certs =
-      CreateCERTCertificateListFromX509CertificateList(certificates);
-  if (nss_certs.empty())
-    return false;
-  return ImportServerCert(nss_certs, trust_bits, not_imported);
-}
-
 NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust(
     const CERTCertificate* cert,
     CertType type) const {
@@ -417,16 +295,6 @@
   }
 }
 
-NSSCertDatabase::TrustBits NSSCertDatabase::GetCertTrust(
-    const X509Certificate* cert,
-    CertType type) const {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  if (!nss_cert)
-    return TRUST_DEFAULT;
-  return GetCertTrust(nss_cert.get(), type);
-}
-
 bool NSSCertDatabase::IsUntrusted(const CERTCertificate* cert) const {
   CERTCertTrust nsstrust;
   SECStatus rv = CERT_GetCertTrust(cert, &nsstrust);
@@ -479,14 +347,6 @@
   return false;
 }
 
-bool NSSCertDatabase::IsUntrusted(const X509Certificate* cert) const {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  if (!nss_cert)
-    return false;
-  return IsUntrusted(nss_cert.get());
-}
-
 bool NSSCertDatabase::SetCertTrust(CERTCertificate* cert,
                                    CertType type,
                                    TrustBits trust_bits) {
@@ -497,16 +357,6 @@
   return success;
 }
 
-bool NSSCertDatabase::SetCertTrust(const X509Certificate* cert,
-                                   CertType type,
-                                   TrustBits trust_bits) {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  if (!nss_cert)
-    return false;
-  return SetCertTrust(nss_cert.get(), type, trust_bits);
-}
-
 bool NSSCertDatabase::DeleteCertAndKey(CERTCertificate* cert) {
   if (!DeleteCertAndKeyImpl(cert))
     return false;
@@ -514,14 +364,6 @@
   return true;
 }
 
-bool NSSCertDatabase::DeleteCertAndKey(X509Certificate* cert) {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  if (!nss_cert)
-    return false;
-  return DeleteCertAndKey(nss_cert.get());
-}
-
 void NSSCertDatabase::DeleteCertAndKeyAsync(
     ScopedCERTCertificate cert,
     const DeleteCertCallback& callback) {
@@ -533,40 +375,16 @@
                      weak_factory_.GetWeakPtr(), callback));
 }
 
-void NSSCertDatabase::DeleteCertAndKeyAsync(
-    const scoped_refptr<X509Certificate>& cert,
-    const DeleteCertCallback& callback) {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert.get());
-  if (!nss_cert) {
-    base::SequencedTaskRunnerHandle::Get()->PostTask(
-        FROM_HERE, base::BindOnce(callback, false));
-  }
-  DeleteCertAndKeyAsync(std::move(nss_cert), callback);
-}
-
 bool NSSCertDatabase::IsReadOnly(const CERTCertificate* cert) const {
   PK11SlotInfo* slot = cert->slot;
   return slot && PK11_IsReadOnly(slot);
 }
 
-bool NSSCertDatabase::IsReadOnly(const X509Certificate* cert) const {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  return nss_cert && IsReadOnly(nss_cert.get());
-}
-
 bool NSSCertDatabase::IsHardwareBacked(const CERTCertificate* cert) const {
   PK11SlotInfo* slot = cert->slot;
   return slot && PK11_IsHW(slot);
 }
 
-bool NSSCertDatabase::IsHardwareBacked(const X509Certificate* cert) const {
-  ScopedCERTCertificate nss_cert =
-      x509_util::CreateCERTCertificateFromX509Certificate(cert);
-  return nss_cert && IsHardwareBacked(nss_cert.get());
-}
-
 void NSSCertDatabase::AddObserver(Observer* observer) {
   observer_list_->AddObserver(observer);
 }
diff --git a/net/cert/nss_cert_database.h b/net/cert/nss_cert_database.h
index 05da157..24907309 100644
--- a/net/cert/nss_cert_database.h
+++ b/net/cert/nss_cert_database.h
@@ -34,10 +34,6 @@
 // Provides functions to manipulate the NSS certificate stores.
 // Forwards notifications about certificate changes to the global CertDatabase
 // singleton.
-//
-// TODO(mattm): some methods have overloads to take either X509Certificate or
-// native NSS types. This is a temporary situation while crbug.com/671420 is in
-// progress. Once 671420 is done, this class will only use NSS native types.
 class NET_EXPORT NSSCertDatabase {
  public:
   class NET_EXPORT Observer {
@@ -95,8 +91,6 @@
 
   typedef base::Callback<void(ScopedCERTCertificateList certs)>
       ListCertsCallback;
-  typedef base::Callback<void(std::unique_ptr<CertificateList> certs)>
-      OldListCertsCallback;
 
   typedef base::Callback<void(bool)> DeleteCertCallback;
 
@@ -117,13 +111,11 @@
   // instance of all certificates).
   // DEPRECATED by |ListCerts|. See http://crbug.com/340460.
   virtual ScopedCERTCertificateList ListCertsSync();
-  void ListCertsSync(CertificateList* certs);
 
   // Asynchronously get a list of unique certificates in the certificate
   // database (one instance of all certificates). Note that the callback may be
   // run even after the database is deleted.
   virtual void ListCerts(const ListCertsCallback& callback);
-  void ListCerts(const OldListCertsCallback& callback);
 
   // Get a list of certificates in the certificate database of the given slot.
   // Note that the callback may be run even after the database is deleted.
@@ -132,8 +124,6 @@
   // thread. Never calls |callback| synchronously.
   virtual void ListCertsInSlot(const ListCertsCallback& callback,
                                PK11SlotInfo* slot);
-  void ListCertsInSlot(const OldListCertsCallback& callback,
-                       PK11SlotInfo* slot);
 
 #if defined(OS_CHROMEOS)
   // Get the slot for system-wide key data. May be NULL if the system token was
@@ -168,18 +158,6 @@
                        const base::string16& password,
                        bool is_extractable,
                        ScopedCERTCertificateList* imported_certs);
-  int ImportFromPKCS12(PK11SlotInfo* slot_info,
-                       const std::string& data,
-                       const base::string16& password,
-                       bool is_extractable,
-                       CertificateList* imported_certs);
-  // Overload on nullptr_t is required as otherwise it would be ambiguous which
-  // of the above methods should be used when nullptr is passed as the last arg.
-  int ImportFromPKCS12(PK11SlotInfo* slot_info,
-                       const std::string& data,
-                       const base::string16& password,
-                       bool is_extractable,
-                       std::nullptr_t /* imported_certs */);
 
   // Export the given certificates and private keys into a PKCS #12 blob,
   // storing into |output|.
@@ -187,9 +165,6 @@
   int ExportToPKCS12(const ScopedCERTCertificateList& certs,
                      const base::string16& password,
                      std::string* output) const;
-  int ExportToPKCS12(const CertificateList& certs,
-                     const base::string16& password,
-                     std::string* output) const;
 
   // Uses similar logic to nsNSSCertificateDB::handleCACertDownload to find the
   // root.  Assumes the list is an ordered hierarchy with the root being either
@@ -197,14 +172,12 @@
   // TODO(mattm): improve this to handle any order.
   CERTCertificate* FindRootInList(
       const ScopedCERTCertificateList& certificates) const;
-  X509Certificate* FindRootInList(const CertificateList& certificates) const;
 
   // Import a user certificate. The private key for the user certificate must
   // already be installed, otherwise we return ERR_NO_PRIVATE_KEY_FOR_CERT.
   // Returns OK or a network error code.
   int ImportUserCert(const std::string& data);
   int ImportUserCert(CERTCertificate* cert);
-  int ImportUserCert(X509Certificate* cert);
 
   // Import CA certificates.
   // Tries to import all the certificates given.  The root will be trusted
@@ -216,9 +189,6 @@
   bool ImportCACerts(const ScopedCERTCertificateList& certificates,
                      TrustBits trust_bits,
                      ImportCertFailureList* not_imported);
-  bool ImportCACerts(const CertificateList& certificates,
-                     TrustBits trust_bits,
-                     ImportCertFailureList* not_imported);
 
   // Import server certificate.  The first cert should be the server cert.  Any
   // additional certs should be intermediate/CA certs and will be imported but
@@ -233,48 +203,35 @@
   bool ImportServerCert(const ScopedCERTCertificateList& certificates,
                         TrustBits trust_bits,
                         ImportCertFailureList* not_imported);
-  bool ImportServerCert(const CertificateList& certificates,
-                        TrustBits trust_bits,
-                        ImportCertFailureList* not_imported);
 
   // Get trust bits for certificate.
   TrustBits GetCertTrust(const CERTCertificate* cert, CertType type) const;
-  TrustBits GetCertTrust(const X509Certificate* cert, CertType type) const;
 
   // IsUntrusted returns true if |cert| is specifically untrusted. These
   // certificates are stored in the database for the specific purpose of
   // rejecting them.
   bool IsUntrusted(const CERTCertificate* cert) const;
-  bool IsUntrusted(const X509Certificate* cert) const;
 
   // Set trust values for certificate.
   // Returns true on success or false on failure.
   bool SetCertTrust(CERTCertificate* cert, CertType type, TrustBits trust_bits);
-  bool SetCertTrust(const X509Certificate* cert,
-                    CertType type,
-                    TrustBits trust_bits);
 
   // Delete certificate and associated private key (if one exists).
   // |cert| is still valid when this function returns. Returns true on
   // success.
   bool DeleteCertAndKey(CERTCertificate* cert);
-  bool DeleteCertAndKey(X509Certificate* cert);
 
   // Like DeleteCertAndKey but does not block by running the removal on a worker
   // thread. This must be called on IO thread and it will run |callback| on IO
   // thread. Never calls |callback| synchronously.
   void DeleteCertAndKeyAsync(ScopedCERTCertificate cert,
                              const DeleteCertCallback& callback);
-  void DeleteCertAndKeyAsync(const scoped_refptr<X509Certificate>& cert,
-                             const DeleteCertCallback& callback);
 
   // Check whether cert is stored in a readonly slot.
   bool IsReadOnly(const CERTCertificate* cert) const;
-  bool IsReadOnly(const X509Certificate* cert) const;
 
   // Check whether cert is stored in a hardware slot.
   bool IsHardwareBacked(const CERTCertificate* cert) const;
-  bool IsHardwareBacked(const X509Certificate* cert) const;
 
   // Overrides task runner that's used for running slow tasks.
   void SetSlowTaskRunnerForTest(
diff --git a/net/cert/x509_util_ios_and_mac.cc b/net/cert/x509_util_ios_and_mac.cc
index ff8faaf..1c77d46 100644
--- a/net/cert/x509_util_ios_and_mac.cc
+++ b/net/cert/x509_util_ios_and_mac.cc
@@ -18,6 +18,14 @@
 
 base::ScopedCFTypeRef<CFMutableArrayRef>
 CreateSecCertificateArrayForX509Certificate(X509Certificate* cert) {
+  return CreateSecCertificateArrayForX509Certificate(
+      cert, InvalidIntermediateBehavior::kFail);
+}
+
+base::ScopedCFTypeRef<CFMutableArrayRef>
+CreateSecCertificateArrayForX509Certificate(
+    X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior) {
   base::ScopedCFTypeRef<CFMutableArrayRef> cert_list(
       CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks));
   if (!cert_list)
@@ -35,8 +43,12 @@
     base::ScopedCFTypeRef<SecCertificateRef> sec_cert(
         CreateSecCertificateFromBytes(CRYPTO_BUFFER_data(intermediate),
                                       CRYPTO_BUFFER_len(intermediate)));
-    if (!sec_cert)
-      return base::ScopedCFTypeRef<CFMutableArrayRef>();
+    if (!sec_cert) {
+      if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
+        return base::ScopedCFTypeRef<CFMutableArrayRef>();
+      LOG(WARNING) << "error parsing intermediate";
+      continue;
+    }
     CFArrayAppendValue(cert_list, sec_cert);
   }
 #else
diff --git a/net/cert/x509_util_ios_and_mac.h b/net/cert/x509_util_ios_and_mac.h
index 4cc9183c..1ca2f7e 100644
--- a/net/cert/x509_util_ios_and_mac.h
+++ b/net/cert/x509_util_ios_and_mac.h
@@ -25,6 +25,22 @@
 NET_EXPORT base::ScopedCFTypeRef<CFMutableArrayRef>
 CreateSecCertificateArrayForX509Certificate(X509Certificate* cert);
 
+// Specify behavior if an intermediate certificate fails SecCertificate
+// parsing. kFail means the function should return a failure result
+// immediately. kIgnore means the invalid intermediate is not added to the
+// output container.
+enum class InvalidIntermediateBehavior { kFail, kIgnore };
+
+// Returns a new CFMutableArrayRef containing this certificate and its
+// intermediate certificates in the form expected by Security.framework
+// and Keychain Services. Returns NULL if the certificate could not be
+// converted. |invalid_intermediate_behavior| specifies behavior if
+// intermediates of |cert| could not be converted.
+NET_EXPORT base::ScopedCFTypeRef<CFMutableArrayRef>
+CreateSecCertificateArrayForX509Certificate(
+    X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior);
+
 }  // namespace x509_util
 
 }  // namespace net
diff --git a/net/cert/x509_util_ios_and_mac_unittest.cc b/net/cert/x509_util_ios_and_mac_unittest.cc
index bab2923..0a65b2b5 100644
--- a/net/cert/x509_util_ios_and_mac_unittest.cc
+++ b/net/cert/x509_util_ios_and_mac_unittest.cc
@@ -5,6 +5,7 @@
 #include "net/cert/x509_util_ios_and_mac.h"
 
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -75,6 +76,49 @@
             BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 3)));
 }
 
+#if BUILDFLAG(USE_BYTE_CERTS)
+TEST(X509UtilTest, CreateSecCertificateArrayForX509CertificateErrors) {
+  scoped_refptr<X509Certificate> ok_cert(
+      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
+  ASSERT_TRUE(ok_cert);
+
+  bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
+      x509_util::CreateCryptoBuffer(base::StringPiece("invalid"));
+  ASSERT_TRUE(bad_cert);
+
+  scoped_refptr<X509Certificate> ok_cert2(
+      ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
+  ASSERT_TRUE(ok_cert);
+
+  scoped_refptr<X509Certificate> cert_with_intermediates(
+      X509Certificate::CreateFromHandle(
+          ok_cert->os_cert_handle(),
+          {bad_cert.get(), ok_cert2->os_cert_handle()}));
+  ASSERT_TRUE(cert_with_intermediates);
+  EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size());
+
+  // Normal CreateSecCertificateArrayForX509Certificate fails with invalid
+  // certs in chain.
+  EXPECT_FALSE(CreateSecCertificateArrayForX509Certificate(
+      cert_with_intermediates.get()));
+
+  // With InvalidIntermediateBehavior::kIgnore, invalid intermediate certs
+  // should be silently dropped.
+  base::ScopedCFTypeRef<CFMutableArrayRef> sec_certs(
+      CreateSecCertificateArrayForX509Certificate(
+          cert_with_intermediates.get(), InvalidIntermediateBehavior::kIgnore));
+  ASSERT_TRUE(sec_certs);
+  ASSERT_EQ(2, CFArrayGetCount(sec_certs.get()));
+  for (int i = 0; i < 2; ++i)
+    ASSERT_TRUE(CFArrayGetValueAtIndex(sec_certs.get(), i));
+
+  EXPECT_EQ(BytesForX509Cert(ok_cert.get()),
+            BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 0)));
+  EXPECT_EQ(BytesForX509Cert(ok_cert2.get()),
+            BytesForSecCert(CFArrayGetValueAtIndex(sec_certs.get(), 1)));
+}
+#endif
+
 TEST(X509UtilTest,
      CreateSecCertificateFromBytesAndCreateX509CertificateFromSecCertificate) {
   CertificateList certs = CreateCertificateListFromFile(
diff --git a/net/cert/x509_util_nss.cc b/net/cert/x509_util_nss.cc
index b32bd38..92dfadf 100644
--- a/net/cert/x509_util_nss.cc
+++ b/net/cert/x509_util_nss.cc
@@ -185,6 +185,13 @@
 
 ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate(
     const X509Certificate* cert) {
+  return x509_util::CreateCERTCertificateListFromX509Certificate(
+      cert, InvalidIntermediateBehavior::kFail);
+}
+
+ScopedCERTCertificateList CreateCERTCertificateListFromX509Certificate(
+    const X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior) {
   ScopedCERTCertificateList nss_chain;
   nss_chain.reserve(1 + cert->GetIntermediateCertificates().size());
 #if BUILDFLAG(USE_BYTE_CERTS)
@@ -197,8 +204,12 @@
        cert->GetIntermediateCertificates()) {
     ScopedCERTCertificate nss_intermediate = CreateCERTCertificateFromBytes(
         CRYPTO_BUFFER_data(intermediate), CRYPTO_BUFFER_len(intermediate));
-    if (!nss_intermediate)
-      return {};
+    if (!nss_intermediate) {
+      if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
+        return {};
+      LOG(WARNING) << "error parsing intermediate";
+      continue;
+    }
     nss_chain.push_back(std::move(nss_intermediate));
   }
 #else
diff --git a/net/cert/x509_util_nss.h b/net/cert/x509_util_nss.h
index 6de1b49..d160995 100644
--- a/net/cert/x509_util_nss.h
+++ b/net/cert/x509_util_nss.h
@@ -46,6 +46,21 @@
 NET_EXPORT ScopedCERTCertificateList
 CreateCERTCertificateListFromX509Certificate(const X509Certificate* cert);
 
+// Specify behavior if an intermediate certificate fails CERTCertificate
+// parsing. kFail means the function should return a failure result
+// immediately. kIgnore means the invalid intermediate is not added to the
+// output container.
+enum class InvalidIntermediateBehavior { kFail, kIgnore };
+
+// Returns a vector of CERTCertificates corresponding to |cert| and its
+// intermediates (if any). Returns an empty vector if the certificate could not
+// be converted. |invalid_intermediate_behavior| specifies behavior if
+// intermediates of |cert| could not be converted.
+NET_EXPORT ScopedCERTCertificateList
+CreateCERTCertificateListFromX509Certificate(
+    const X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior);
+
 // Parses all of the certificates possible from |data|. |format| is a
 // bit-wise OR of X509Certificate::Format, indicating the possible formats the
 // certificates may have been serialized as. If an error occurs, an empty
diff --git a/net/cert/x509_util_nss_unittest.cc b/net/cert/x509_util_nss_unittest.cc
index 3b6af5d..5b1baf47 100644
--- a/net/cert/x509_util_nss_unittest.cc
+++ b/net/cert/x509_util_nss_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/files/file_util.h"
 #include "net/cert/scoped_nss_types.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_certificate_data.h"
 #include "net/test/test_data_directory.h"
@@ -138,6 +139,50 @@
             BytesForNSSCert(nss_certs[3].get()));
 }
 
+#if BUILDFLAG(USE_BYTE_CERTS)
+TEST(X509UtilTest, CreateCERTCertificateListFromX509CertificateErrors) {
+  scoped_refptr<X509Certificate> ok_cert(
+      ImportCertFromFile(GetTestCertsDirectory(), "ok_cert.pem"));
+  ASSERT_TRUE(ok_cert);
+
+  bssl::UniquePtr<CRYPTO_BUFFER> bad_cert =
+      x509_util::CreateCryptoBuffer(base::StringPiece("invalid"));
+  ASSERT_TRUE(bad_cert);
+
+  scoped_refptr<X509Certificate> ok_cert2(
+      ImportCertFromFile(GetTestCertsDirectory(), "root_ca_cert.pem"));
+  ASSERT_TRUE(ok_cert);
+
+  scoped_refptr<X509Certificate> cert_with_intermediates(
+      X509Certificate::CreateFromHandle(
+          ok_cert->os_cert_handle(),
+          {bad_cert.get(), ok_cert2->os_cert_handle()}));
+  ASSERT_TRUE(cert_with_intermediates);
+  EXPECT_EQ(2U, cert_with_intermediates->GetIntermediateCertificates().size());
+
+  // Normal CreateCERTCertificateListFromX509Certificate fails with invalid
+  // certs in chain.
+  ScopedCERTCertificateList nss_certs =
+      x509_util::CreateCERTCertificateListFromX509Certificate(
+          cert_with_intermediates.get());
+  EXPECT_TRUE(nss_certs.empty());
+
+  // With InvalidIntermediateBehavior::kIgnore, invalid intermediate certs
+  // should be silently dropped.
+  nss_certs = x509_util::CreateCERTCertificateListFromX509Certificate(
+      cert_with_intermediates.get(),
+      x509_util::InvalidIntermediateBehavior::kIgnore);
+  ASSERT_EQ(2U, nss_certs.size());
+  for (const auto& nss_cert : nss_certs)
+    ASSERT_TRUE(nss_cert.get());
+
+  EXPECT_EQ(BytesForX509Cert(ok_cert.get()),
+            BytesForNSSCert(nss_certs[0].get()));
+  EXPECT_EQ(BytesForX509Cert(ok_cert2.get()),
+            BytesForNSSCert(nss_certs[1].get()));
+}
+#endif
+
 TEST(X509UtilNSSTest, CreateCERTCertificateListFromBytes) {
   base::FilePath cert_path =
       GetTestCertsDirectory().AppendASCII("multi-root-chain1.pem");
@@ -288,12 +333,12 @@
 TEST(X509UtilNSSTest, GetDefaultNickname) {
   base::FilePath certs_dir = GetTestCertsDirectory();
 
-  scoped_refptr<X509Certificate> test_cert(
-      ImportCertFromFile(certs_dir, "no_subject_common_name_cert.pem"));
+  ScopedCERTCertificate test_cert = ImportCERTCertificateFromFile(
+      certs_dir, "no_subject_common_name_cert.pem");
   ASSERT_TRUE(test_cert);
 
   std::string nickname = x509_util::GetDefaultUniqueNickname(
-      test_cert->os_cert_handle(), USER_CERT, nullptr /*slot*/);
+      test_cert.get(), USER_CERT, nullptr /*slot*/);
   EXPECT_EQ(
       "wtc@google.com's COMODO Client Authentication and "
       "Secure Email CA ID",
@@ -303,26 +348,30 @@
 TEST(X509UtilNSSTest, GetCERTNameDisplayName_CN) {
   base::FilePath certs_dir = GetTestCertsDirectory();
 
-  scoped_refptr<X509Certificate> test_cert(
-      ImportCertFromFile(certs_dir, "ok_cert.pem"));
+  ScopedCERTCertificate test_cert =
+      ImportCERTCertificateFromFile(certs_dir, "ok_cert.pem");
   ASSERT_TRUE(test_cert);
+  scoped_refptr<X509Certificate> x509_test_cert =
+      ImportCertFromFile(certs_dir, "ok_cert.pem");
+  ASSERT_TRUE(x509_test_cert);
 
-  std::string name =
-      x509_util::GetCERTNameDisplayName(&test_cert->os_cert_handle()->subject);
+  std::string name = x509_util::GetCERTNameDisplayName(&test_cert->subject);
   EXPECT_EQ("127.0.0.1", name);
-  EXPECT_EQ(test_cert->subject().GetDisplayName(), name);
+  EXPECT_EQ(x509_test_cert->subject().GetDisplayName(), name);
 }
 
 TEST(X509UtilNSSTest, GetCERTNameDisplayName_O) {
   base::FilePath certs_dir =
       GetTestNetDataDirectory().AppendASCII("parse_certificate_unittest");
 
-  scoped_refptr<X509Certificate> test_cert(
-      ImportCertFromFile(certs_dir, "subject_t61string.pem"));
+  ScopedCERTCertificate test_cert =
+      ImportCERTCertificateFromFile(certs_dir, "subject_t61string.pem");
   ASSERT_TRUE(test_cert);
+  scoped_refptr<X509Certificate> x509_test_cert =
+      ImportCertFromFile(certs_dir, "subject_t61string.pem");
+  ASSERT_TRUE(x509_test_cert);
 
-  std::string name =
-      x509_util::GetCERTNameDisplayName(&test_cert->os_cert_handle()->subject);
+  std::string name = x509_util::GetCERTNameDisplayName(&test_cert->subject);
   EXPECT_EQ(
       " !\"#$%&'()*+,-./"
       "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`"
@@ -330,7 +379,7 @@
       " ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæç"
       "èéêëìíîïðñòóôõö÷øùúûüýþÿ",
       name);
-  EXPECT_EQ(test_cert->subject().GetDisplayName(), name);
+  EXPECT_EQ(x509_test_cert->subject().GetDisplayName(), name);
 }
 
 TEST(X509UtilNSSTest, ParseClientSubjectAltNames) {
@@ -338,18 +387,17 @@
 
   // This cert contains one rfc822Name field, and one Microsoft UPN
   // otherName field.
-  scoped_refptr<X509Certificate> san_cert =
-      ImportCertFromFile(certs_dir, "client_3.pem");
-  ASSERT_NE(static_cast<X509Certificate*>(NULL), san_cert.get());
+  ScopedCERTCertificate san_cert =
+      ImportCERTCertificateFromFile(certs_dir, "client_3.pem");
+  ASSERT_TRUE(san_cert);
 
   std::vector<std::string> rfc822_names;
-  x509_util::GetRFC822SubjectAltNames(san_cert->os_cert_handle(),
-                                      &rfc822_names);
+  x509_util::GetRFC822SubjectAltNames(san_cert.get(), &rfc822_names);
   ASSERT_EQ(1U, rfc822_names.size());
   EXPECT_EQ("santest@example.com", rfc822_names[0]);
 
   std::vector<std::string> upn_names;
-  x509_util::GetUPNSubjectAltNames(san_cert->os_cert_handle(), &upn_names);
+  x509_util::GetUPNSubjectAltNames(san_cert.get(), &upn_names);
   ASSERT_EQ(1U, upn_names.size());
   EXPECT_EQ("santest@ad.corp.example.com", upn_names[0]);
 }
diff --git a/net/cert/x509_util_win.cc b/net/cert/x509_util_win.cc
index 4b1f74d..a2181c9d 100644
--- a/net/cert/x509_util_win.cc
+++ b/net/cert/x509_util_win.cc
@@ -58,6 +58,12 @@
 }
 
 ScopedPCCERT_CONTEXT CreateCertContextWithChain(const X509Certificate* cert) {
+  return CreateCertContextWithChain(cert, InvalidIntermediateBehavior::kFail);
+}
+
+ScopedPCCERT_CONTEXT CreateCertContextWithChain(
+    const X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior) {
   // Create an in-memory certificate store to hold the certificate and its
   // intermediate certificates. The store will be referenced in the returned
   // PCCERT_CONTEXT, and will not be freed until the PCCERT_CONTEXT is freed.
@@ -85,8 +91,11 @@
         store.get(), X509_ASN_ENCODING, CRYPTO_BUFFER_data(intermediate),
         base::checked_cast<DWORD>(CRYPTO_BUFFER_len(intermediate)),
         CERT_STORE_ADD_ALWAYS, NULL);
-    if (!ok)
-      return nullptr;
+    if (!ok) {
+      if (invalid_intermediate_behavior == InvalidIntermediateBehavior::kFail)
+        return nullptr;
+      LOG(WARNING) << "error parsing intermediate";
+    }
   }
 #else
   PCCERT_CONTEXT os_cert_handle = cert->os_cert_handle();
diff --git a/net/cert/x509_util_win.h b/net/cert/x509_util_win.h
index e3d0d947..f9968a1 100644
--- a/net/cert/x509_util_win.h
+++ b/net/cert/x509_util_win.h
@@ -79,6 +79,17 @@
 NET_EXPORT ScopedPCCERT_CONTEXT
 CreateCertContextWithChain(const X509Certificate* cert);
 
+// Specify behavior if an intermediate certificate fails CERT_CONTEXT parsing.
+// kFail means the function should return a failure result immediately. kIgnore
+// means the invalid intermediate is not added to the output context.
+enum class InvalidIntermediateBehavior { kFail, kIgnore };
+
+// As CreateCertContextWithChain above, but |invalid_intermediate_behavior|
+// specifies behavior if intermediates of |cert| could not be converted.
+NET_EXPORT ScopedPCCERT_CONTEXT CreateCertContextWithChain(
+    const X509Certificate* cert,
+    InvalidIntermediateBehavior invalid_intermediate_behavior);
+
 // Calculates the SHA-256 fingerprint of the certificate.  Returns an empty
 // (all zero) fingerprint on failure.
 NET_EXPORT SHA256HashValue CalculateFingerprint256(PCCERT_CONTEXT cert);
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
index 98e9188..d894662 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.cc
@@ -132,7 +132,7 @@
   UMA_HISTOGRAM_COUNTS_1000("Memory.Experimental.Debug.GlobalDumpQueueLength",
                             queued_memory_dump_requests_.size());
 
-  bool another_dump_already_in_progress = !queued_memory_dump_requests_.empty();
+  bool another_dump_is_queued = !queued_memory_dump_requests_.empty();
 
   // TODO(primiano): remove dump_guid from the request. For the moment callers
   // should just pass a zero |dump_guid| in input. It should be an out-only arg.
@@ -143,7 +143,7 @@
   // If this is a periodic or peak memory dump request and there already is
   // another request in the queue with the same level of detail, there's no
   // point in enqueuing this request.
-  if (another_dump_already_in_progress &&
+  if (another_dump_is_queued &&
       args.dump_type !=
           base::trace_event::MemoryDumpType::EXPLICITLY_TRIGGERED &&
       args.dump_type != base::trace_event::MemoryDumpType::SUMMARY_ONLY &&
@@ -166,9 +166,9 @@
 
   queued_memory_dump_requests_.emplace_back(args, callback);
 
-  // If another dump is already in progress, this dump will automatically be
+  // If another dump is already in queued, this dump will automatically be
   // scheduled when the other dump finishes.
-  if (another_dump_already_in_progress)
+  if (another_dump_is_queued)
     return;
 
   PerformNextQueuedGlobalMemoryDump();
@@ -224,8 +224,6 @@
         continue;
       RemovePendingResponse(client_process, current->type);
       request->failed_memory_dump_count++;
-      // Regression test (crbug.com/742265).
-      DCHECK(GetCurrentRequest());
     }
     FinalizeGlobalMemoryDumpIfAllManagersReplied();
   }
@@ -237,10 +235,8 @@
   using ResponseType = QueuedMemoryDumpRequest::PendingResponse::Type;
   DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
   QueuedMemoryDumpRequest* request = GetCurrentRequest();
-  if (request == nullptr) {
-    NOTREACHED() << "No current dump request.";
-    return;
-  }
+  DCHECK(!request->dump_in_progress);
+  request->dump_in_progress = true;
 
   const bool wants_mmaps = request->args.level_of_detail ==
                            base::trace_event::MemoryDumpLevelOfDetail::DETAILED;
@@ -425,7 +421,7 @@
 void CoordinatorImpl::FinalizeGlobalMemoryDumpIfAllManagersReplied() {
   DCHECK(!queued_memory_dump_requests_.empty());
   QueuedMemoryDumpRequest* request = &queued_memory_dump_requests_.front();
-  if (request->pending_responses.size() > 0)
+  if (!request->dump_in_progress || request->pending_responses.size() > 0)
     return;
 
   // Reconstruct a map of pid -> ProcessMemoryDump by reassembling the responses
diff --git a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
index fea0b53..ca4512e2 100644
--- a/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
+++ b/services/resource_coordinator/memory_instrumentation/coordinator_impl.h
@@ -107,6 +107,7 @@
     std::set<QueuedMemoryDumpRequest::PendingResponse> pending_responses;
     std::map<mojom::ClientProcess*, Response> responses;
     int failed_memory_dump_count = 0;
+    bool dump_in_progress = false;
     // The time we started handling the request (does not including queuing
     // time).
     base::Time start_time;
diff --git a/services/ui/gpu/interfaces/BUILD.gn b/services/ui/gpu/interfaces/BUILD.gn
index d846084..22e4e79 100644
--- a/services/ui/gpu/interfaces/BUILD.gn
+++ b/services/ui/gpu/interfaces/BUILD.gn
@@ -12,7 +12,6 @@
   ]
 
   public_deps = [
-    "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
     "//media/gpu/mojo:jpeg_decoder",
     "//media/mojo/interfaces",
diff --git a/services/ui/public/interfaces/BUILD.gn b/services/ui/public/interfaces/BUILD.gn
index 7781020..19ad8af 100644
--- a/services/ui/public/interfaces/BUILD.gn
+++ b/services/ui/public/interfaces/BUILD.gn
@@ -31,7 +31,6 @@
 
   public_deps = [
     ":constants",
-    "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
     "//media/gpu/mojo:jpeg_decoder",
     "//media/mojo/interfaces",
diff --git a/services/ui/ws/BUILD.gn b/services/ui/ws/BUILD.gn
index 3956b3c..0b7f9d8 100644
--- a/services/ui/ws/BUILD.gn
+++ b/services/ui/ws/BUILD.gn
@@ -133,7 +133,6 @@
   public_deps = [
     "//base",
     "//cc",
-    "//cc/ipc:interfaces",
     "//components/viz/common",
     "//components/viz/host",
     "//components/viz/service",
diff --git a/services/ui/ws/server_window.cc b/services/ui/ws/server_window.cc
index f8e6006..9932521e 100644
--- a/services/ui/ws/server_window.cc
+++ b/services/ui/ws/server_window.cc
@@ -51,8 +51,12 @@
   // TODO(kylechar): Add method to reregister |frame_sink_id_| when viz service
   // has crashed.
   auto* host_frame_sink_manager = delegate_->GetHostFrameSinkManager();
-  if (host_frame_sink_manager)
+  if (host_frame_sink_manager) {
     host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+    host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_, GetName());
+#endif
+  }
 }
 
 ServerWindow::~ServerWindow() {
@@ -390,6 +394,11 @@
   } else if (it != properties_.end()) {
     properties_.erase(it);
   }
+#if DCHECK_IS_ON()
+  auto* host_frame_sink_manager = delegate_->GetHostFrameSinkManager();
+  if (host_frame_sink_manager && name == mojom::WindowManager::kName_Property)
+    host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_, GetName());
+#endif
 
   for (auto& observer : observers_)
     observer.OnWindowSharedPropertyChanged(this, name, value);
diff --git a/services/viz/privileged/interfaces/compositing/BUILD.gn b/services/viz/privileged/interfaces/compositing/BUILD.gn
index 2144b19..a7d8493 100644
--- a/services/viz/privileged/interfaces/compositing/BUILD.gn
+++ b/services/viz/privileged/interfaces/compositing/BUILD.gn
@@ -11,7 +11,6 @@
   ]
 
   public_deps = [
-    "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
     "//mojo/common:common_custom_types",
     "//services/viz/public/interfaces",
diff --git a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
index 07069594..f24fde96 100644
--- a/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
+++ b/services/viz/privileged/interfaces/compositing/frame_sink_manager.mojom
@@ -40,8 +40,10 @@
 // frame sink manager host which will forward the request to the frame sink
 // manager.
 interface FrameSinkManager {
-  // Registers |frame_sink_id| will be used. This must be called before
-  // Create(Root)CompositorFrameSink() is called.
+  // Starts the scope of temporary references tied to this |frame_sink_id|.
+  // Temporary references tied to this |frame_sink_id| will be dropped on
+  // InvalidateFrameSinkId.This must be called before Create(Root)
+  // CompositorFrameSink() is called.
   RegisterFrameSinkId(FrameSinkId frame_sink_id);
 
   // Invalidates |frame_sink_id| which cleans up any unsatisified surface
@@ -50,6 +52,10 @@
   // message pipe to the client will be closed.
   InvalidateFrameSinkId(FrameSinkId frame_sink_id);
 
+  // |debug_label| is used when printing out the surface hierarchy so we know
+  // which clients are contributing which surfaces.
+  SetFrameSinkDebugLabel(FrameSinkId frame_sink_id, string debug_label);
+
   // Create a CompositorFrameSink for a privileged client (e.g. WindowServer).
   // This is only used by privileged clients. The client can call methods that
   // talks to the Display (e.g. ResizeDisplay(), SetDisplayVisible(), etc)
diff --git a/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
index ad979fe..01522616 100644
--- a/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
+++ b/services/viz/public/cpp/compositing/compositor_frame_for_blink.typemap
@@ -26,7 +26,6 @@
 ]
 public_deps = [
   "//cc",
-  "//cc/ipc:interfaces",
   "//gpu/ipc/common:interfaces",
   "//mojo/common:common_custom_types",
   "//services/viz/public/interfaces",
diff --git a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
index db17619..28f6ef9a 100644
--- a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.cc
@@ -7,8 +7,8 @@
 #include <utility>
 
 #include "base/bind.h"
-#include "cc/ipc/copy_output_result_struct_traits.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
+#include "services/viz/public/cpp/compositing/copy_output_result_struct_traits.h"
 
 namespace {
 
diff --git a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
index ca33fa43..b592dae 100644
--- a/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
+++ b/services/viz/public/cpp/compositing/copy_output_request_struct_traits.h
@@ -5,9 +5,9 @@
 #ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COPY_OUTPUT_REQUEST_STRUCT_TRAITS_H_
 #define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COPY_OUTPUT_REQUEST_STRUCT_TRAITS_H_
 
-#include "cc/ipc/texture_mailbox_struct_traits.h"
 #include "components/viz/common/quads/copy_output_request.h"
 #include "mojo/common/common_custom_types_struct_traits.h"
+#include "services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/copy_output_request.mojom.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 
diff --git a/services/viz/public/cpp/compositing/copy_output_result.typemap b/services/viz/public/cpp/compositing/copy_output_result.typemap
new file mode 100644
index 0000000..4d2cb48a
--- /dev/null
+++ b/services/viz/public/cpp/compositing/copy_output_result.typemap
@@ -0,0 +1,16 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/viz/public/interfaces/compositing/copy_output_result.mojom"
+public_headers = [ "//components/viz/common/quads/copy_output_result.h" ]
+traits_headers = [ "//services/viz/public/cpp/compositing/copy_output_result_struct_traits.h" ]
+public_deps = [
+  "//cc",
+  "//components/viz/common",
+  "//skia/public/interfaces:struct_traits",
+]
+sources = [
+  "//services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc",
+]
+type_mappings = [ "viz.mojom.CopyOutputResult=std::unique_ptr<viz::CopyOutputResult>[move_only]" ]
diff --git a/cc/ipc/copy_output_result_struct_traits.cc b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
similarity index 86%
rename from cc/ipc/copy_output_result_struct_traits.cc
rename to services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
index 1fb5d96c..704e2ee0 100644
--- a/cc/ipc/copy_output_result_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "cc/ipc/copy_output_result_struct_traits.h"
+#include "services/viz/public/cpp/compositing/copy_output_result_struct_traits.h"
 
 #include "mojo/public/cpp/bindings/strong_binding.h"
 
@@ -14,7 +14,7 @@
 // serializable). Once the client calls Release, the release_callback_ will be
 // called. An object of this class will remain alive until the MessagePipe
 // attached to it goes away (i.e. StrongBinding is used).
-class TextureMailboxReleaserImpl : public cc::mojom::TextureMailboxReleaser {
+class TextureMailboxReleaserImpl : public viz::mojom::TextureMailboxReleaser {
  public:
   explicit TextureMailboxReleaserImpl(
       std::unique_ptr<viz::SingleReleaseCallback> release_callback)
@@ -41,7 +41,7 @@
   std::unique_ptr<viz::SingleReleaseCallback> release_callback_;
 };
 
-void Release(cc::mojom::TextureMailboxReleaserPtr ptr,
+void Release(viz::mojom::TextureMailboxReleaserPtr ptr,
              const gpu::SyncToken& sync_token,
              bool is_lost) {
   ptr->Release(sync_token, is_lost);
@@ -52,11 +52,11 @@
 namespace mojo {
 
 // static
-cc::mojom::TextureMailboxReleaserPtr
-StructTraits<cc::mojom::CopyOutputResultDataView,
+viz::mojom::TextureMailboxReleaserPtr
+StructTraits<viz::mojom::CopyOutputResultDataView,
              std::unique_ptr<viz::CopyOutputResult>>::
     releaser(const std::unique_ptr<viz::CopyOutputResult>& result) {
-  cc::mojom::TextureMailboxReleaserPtr releaser;
+  viz::mojom::TextureMailboxReleaserPtr releaser;
   if (HasTextureResult(*result)) {
     MakeStrongBinding(std::make_unique<TextureMailboxReleaserImpl>(
                           result->TakeTextureOwnership()),
@@ -66,16 +66,16 @@
 }
 
 // static
-bool StructTraits<cc::mojom::CopyOutputResultDataView,
+bool StructTraits<viz::mojom::CopyOutputResultDataView,
                   std::unique_ptr<viz::CopyOutputResult>>::
     HasTextureResult(const viz::CopyOutputResult& result) {
   return result.GetTextureMailbox() && result.GetTextureMailbox()->IsTexture();
 }
 
 // static
-bool StructTraits<cc::mojom::CopyOutputResultDataView,
+bool StructTraits<viz::mojom::CopyOutputResultDataView,
                   std::unique_ptr<viz::CopyOutputResult>>::
-    Read(cc::mojom::CopyOutputResultDataView data,
+    Read(viz::mojom::CopyOutputResultDataView data,
          std::unique_ptr<viz::CopyOutputResult>* out_p) {
   // First read into local variables, and then instantiate an appropriate
   // implementation of viz::CopyOutputResult.
@@ -102,7 +102,7 @@
         return false;
       if (texture_mailbox && texture_mailbox->IsTexture()) {
         auto releaser =
-            data.TakeReleaser<cc::mojom::TextureMailboxReleaserPtr>();
+            data.TakeReleaser<viz::mojom::TextureMailboxReleaserPtr>();
         if (!releaser)
           return false;  // Illegal to provide texture without Releaser.
         out_p->reset(new viz::CopyOutputTextureResult(
diff --git a/cc/ipc/copy_output_result_struct_traits.h b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
similarity index 61%
rename from cc/ipc/copy_output_result_struct_traits.h
rename to services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
index cd265bb..9a09175 100644
--- a/cc/ipc/copy_output_result_struct_traits.h
+++ b/services/viz/public/cpp/compositing/copy_output_result_struct_traits.h
@@ -2,40 +2,40 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_IPC_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
-#define CC_IPC_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
 
-#include "cc/ipc/copy_output_result.mojom-shared.h"
-#include "cc/ipc/texture_mailbox_releaser.mojom.h"
-#include "cc/ipc/texture_mailbox_struct_traits.h"
 #include "components/viz/common/quads/copy_output_result.h"
+#include "services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h"
+#include "services/viz/public/interfaces/compositing/copy_output_result.mojom-shared.h"
+#include "services/viz/public/interfaces/compositing/texture_mailbox_releaser.mojom.h"
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 
 namespace mojo {
 
 template <>
-struct EnumTraits<cc::mojom::CopyOutputResultFormat,
+struct EnumTraits<viz::mojom::CopyOutputResultFormat,
                   viz::CopyOutputResult::Format> {
-  static cc::mojom::CopyOutputResultFormat ToMojom(
+  static viz::mojom::CopyOutputResultFormat ToMojom(
       viz::CopyOutputResult::Format format) {
     switch (format) {
       case viz::CopyOutputResult::Format::RGBA_BITMAP:
-        return cc::mojom::CopyOutputResultFormat::RGBA_BITMAP;
+        return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
       case viz::CopyOutputResult::Format::RGBA_TEXTURE:
-        return cc::mojom::CopyOutputResultFormat::RGBA_TEXTURE;
+        return viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE;
     }
     NOTREACHED();
-    return cc::mojom::CopyOutputResultFormat::RGBA_BITMAP;
+    return viz::mojom::CopyOutputResultFormat::RGBA_BITMAP;
   }
 
-  static bool FromMojom(cc::mojom::CopyOutputResultFormat input,
+  static bool FromMojom(viz::mojom::CopyOutputResultFormat input,
                         viz::CopyOutputResult::Format* out) {
     switch (input) {
-      case cc::mojom::CopyOutputResultFormat::RGBA_BITMAP:
+      case viz::mojom::CopyOutputResultFormat::RGBA_BITMAP:
         *out = viz::CopyOutputResult::Format::RGBA_BITMAP;
         return true;
-      case cc::mojom::CopyOutputResultFormat::RGBA_TEXTURE:
+      case viz::mojom::CopyOutputResultFormat::RGBA_TEXTURE:
         *out = viz::CopyOutputResult::Format::RGBA_TEXTURE;
         return true;
     }
@@ -44,7 +44,7 @@
 };
 
 template <>
-struct StructTraits<cc::mojom::CopyOutputResultDataView,
+struct StructTraits<viz::mojom::CopyOutputResultDataView,
                     std::unique_ptr<viz::CopyOutputResult>> {
   static viz::CopyOutputResult::Format format(
       const std::unique_ptr<viz::CopyOutputResult>& result) {
@@ -69,10 +69,10 @@
       return base::nullopt;
   }
 
-  static cc::mojom::TextureMailboxReleaserPtr releaser(
+  static viz::mojom::TextureMailboxReleaserPtr releaser(
       const std::unique_ptr<viz::CopyOutputResult>& result);
 
-  static bool Read(cc::mojom::CopyOutputResultDataView data,
+  static bool Read(viz::mojom::CopyOutputResultDataView data,
                    std::unique_ptr<viz::CopyOutputResult>* out_p);
 
  private:
@@ -81,4 +81,4 @@
 
 }  // namespace mojo
 
-#endif  // CC_IPC_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_COPY_OUTPUT_RESULT_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.cc b/services/viz/public/cpp/compositing/quads_struct_traits.cc
index 23bcfc2..a52a851 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.cc
@@ -8,42 +8,42 @@
 
 namespace mojo {
 
-cc::DrawQuad* AllocateAndConstruct(
+viz::DrawQuad* AllocateAndConstruct(
     viz::mojom::DrawQuadStateDataView::Tag material,
     cc::QuadList* list) {
-  cc::DrawQuad* quad = nullptr;
+  viz::DrawQuad* quad = nullptr;
   switch (material) {
     case viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::DebugBorderDrawQuad>();
-      quad->material = cc::DrawQuad::DEBUG_BORDER;
+      quad->material = viz::DrawQuad::DEBUG_BORDER;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::RENDER_PASS_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::RenderPassDrawQuad>();
-      quad->material = cc::DrawQuad::RENDER_PASS;
+      quad->material = viz::DrawQuad::RENDER_PASS;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::SOLID_COLOR_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::SolidColorDrawQuad>();
-      quad->material = cc::DrawQuad::SOLID_COLOR;
+      quad->material = viz::DrawQuad::SOLID_COLOR;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::STREAM_VIDEO_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::StreamVideoDrawQuad>();
-      quad->material = cc::DrawQuad::STREAM_VIDEO_CONTENT;
+      quad->material = viz::DrawQuad::STREAM_VIDEO_CONTENT;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::SURFACE_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::SurfaceDrawQuad>();
-      quad->material = cc::DrawQuad::SURFACE_CONTENT;
+      quad->material = viz::DrawQuad::SURFACE_CONTENT;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::TEXTURE_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::TextureDrawQuad>();
-      quad->material = cc::DrawQuad::TEXTURE_CONTENT;
+      quad->material = viz::DrawQuad::TEXTURE_CONTENT;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::TILE_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::TileDrawQuad>();
-      quad->material = cc::DrawQuad::TILED_CONTENT;
+      quad->material = viz::DrawQuad::TILED_CONTENT;
       return quad;
     case viz::mojom::DrawQuadStateDataView::Tag::YUV_VIDEO_QUAD_STATE:
       quad = list->AllocateAndConstruct<cc::YUVVideoDrawQuad>();
-      quad->material = cc::DrawQuad::YUV_VIDEO_CONTENT;
+      quad->material = viz::DrawQuad::YUV_VIDEO_CONTENT;
       return quad;
   }
   NOTREACHED();
@@ -51,9 +51,8 @@
 }
 
 // static
-bool StructTraits<viz::mojom::DebugBorderQuadStateDataView, cc::DrawQuad>::Read(
-    viz::mojom::DebugBorderQuadStateDataView data,
-    cc::DrawQuad* out) {
+bool StructTraits<viz::mojom::DebugBorderQuadStateDataView, viz::DrawQuad>::
+    Read(viz::mojom::DebugBorderQuadStateDataView data, viz::DrawQuad* out) {
   cc::DebugBorderDrawQuad* quad = static_cast<cc::DebugBorderDrawQuad*>(out);
   quad->color = data.color();
   quad->width = data.width();
@@ -61,9 +60,9 @@
 }
 
 // static
-bool StructTraits<viz::mojom::RenderPassQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::RenderPassQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::RenderPassQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::RenderPassDrawQuad* quad = static_cast<cc::RenderPassDrawQuad*>(out);
   quad->resources.ids[cc::RenderPassDrawQuad::kMaskResourceIdIndex] =
       data.mask_resource_id();
@@ -80,9 +79,9 @@
 }
 
 // static
-bool StructTraits<viz::mojom::SolidColorQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::SolidColorQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::SolidColorQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::SolidColorDrawQuad* quad = static_cast<cc::SolidColorDrawQuad*>(out);
   quad->force_anti_aliasing_off = data.force_anti_aliasing_off();
   quad->color = data.color();
@@ -90,9 +89,8 @@
 }
 
 // static
-bool StructTraits<viz::mojom::StreamVideoQuadStateDataView, cc::DrawQuad>::Read(
-    viz::mojom::StreamVideoQuadStateDataView data,
-    cc::DrawQuad* out) {
+bool StructTraits<viz::mojom::StreamVideoQuadStateDataView, viz::DrawQuad>::
+    Read(viz::mojom::StreamVideoQuadStateDataView data, viz::DrawQuad* out) {
   cc::StreamVideoDrawQuad* quad = static_cast<cc::StreamVideoDrawQuad*>(out);
   quad->resources.ids[cc::StreamVideoDrawQuad::kResourceIdIndex] =
       data.resource_id();
@@ -133,18 +131,18 @@
 }
 
 // static
-bool StructTraits<viz::mojom::SurfaceQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::SurfaceQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::SurfaceQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::SurfaceDrawQuad* quad = static_cast<cc::SurfaceDrawQuad*>(out);
   return data.ReadSurfaceDrawQuadType(&quad->surface_draw_quad_type) &&
          data.ReadSurface(&quad->surface_id);
 }
 
 // static
-bool StructTraits<viz::mojom::TextureQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::TextureQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::TextureDrawQuad* quad = static_cast<cc::TextureDrawQuad*>(out);
 
   quad->resources.ids[cc::TextureDrawQuad::kResourceIdIndex] =
@@ -173,9 +171,9 @@
 }
 
 // static
-bool StructTraits<viz::mojom::TileQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::TileQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::TileQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::TileDrawQuad* quad = static_cast<cc::TileDrawQuad*>(out);
   if (!data.ReadTexCoordRect(&quad->tex_coord_rect) ||
       !data.ReadTextureSize(&quad->texture_size)) {
@@ -223,9 +221,9 @@
 }
 
 // static
-bool StructTraits<viz::mojom::YUVVideoQuadStateDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::YUVVideoQuadStateDataView, viz::DrawQuad>::Read(
     viz::mojom::YUVVideoQuadStateDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   cc::YUVVideoDrawQuad* quad = static_cast<cc::YUVVideoDrawQuad*>(out);
   if (!data.ReadYaTexCoordRect(&quad->ya_tex_coord_rect) ||
       !data.ReadUvTexCoordRect(&quad->uv_tex_coord_rect) ||
@@ -243,7 +241,7 @@
   quad->resources.ids[cc::YUVVideoDrawQuad::kAPlaneResourceIdIndex] =
       data.a_plane_resource_id();
   static_assert(cc::YUVVideoDrawQuad::kAPlaneResourceIdIndex ==
-                    cc::DrawQuad::Resources::kMaxResourceIdCount - 1,
+                    viz::DrawQuad::Resources::kMaxResourceIdCount - 1,
                 "The A plane resource should be the last resource ID.");
   quad->resources.count = data.a_plane_resource_id() ? 4 : 3;
 
@@ -261,9 +259,9 @@
 }
 
 // static
-bool StructTraits<viz::mojom::DrawQuadDataView, cc::DrawQuad>::Read(
+bool StructTraits<viz::mojom::DrawQuadDataView, viz::DrawQuad>::Read(
     viz::mojom::DrawQuadDataView data,
-    cc::DrawQuad* out) {
+    viz::DrawQuad* out) {
   if (!data.ReadRect(&out->rect) || !data.ReadVisibleRect(&out->visible_rect)) {
     return false;
   }
diff --git a/services/viz/public/cpp/compositing/quads_struct_traits.h b/services/viz/public/cpp/compositing/quads_struct_traits.h
index f81ecbf..9e7dff1 100644
--- a/services/viz/public/cpp/compositing/quads_struct_traits.h
+++ b/services/viz/public/cpp/compositing/quads_struct_traits.h
@@ -26,73 +26,77 @@
 
 namespace mojo {
 
-cc::DrawQuad* AllocateAndConstruct(
+viz::DrawQuad* AllocateAndConstruct(
     viz::mojom::DrawQuadStateDataView::Tag material,
     cc::QuadList* list);
 
 template <>
-struct UnionTraits<viz::mojom::DrawQuadStateDataView, cc::DrawQuad> {
+struct UnionTraits<viz::mojom::DrawQuadStateDataView, viz::DrawQuad> {
   static viz::mojom::DrawQuadStateDataView::Tag GetTag(
-      const cc::DrawQuad& quad) {
+      const viz::DrawQuad& quad) {
     switch (quad.material) {
-      case cc::DrawQuad::INVALID:
+      case viz::DrawQuad::INVALID:
         break;
-      case cc::DrawQuad::DEBUG_BORDER:
+      case viz::DrawQuad::DEBUG_BORDER:
         return viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE;
-      case cc::DrawQuad::PICTURE_CONTENT:
+      case viz::DrawQuad::PICTURE_CONTENT:
         break;
-      case cc::DrawQuad::RENDER_PASS:
+      case viz::DrawQuad::RENDER_PASS:
         return viz::mojom::DrawQuadStateDataView::Tag::RENDER_PASS_QUAD_STATE;
-      case cc::DrawQuad::SOLID_COLOR:
+      case viz::DrawQuad::SOLID_COLOR:
         return viz::mojom::DrawQuadStateDataView::Tag::SOLID_COLOR_QUAD_STATE;
-      case cc::DrawQuad::STREAM_VIDEO_CONTENT:
+      case viz::DrawQuad::STREAM_VIDEO_CONTENT:
         return viz::mojom::DrawQuadStateDataView::Tag::STREAM_VIDEO_QUAD_STATE;
-      case cc::DrawQuad::SURFACE_CONTENT:
+      case viz::DrawQuad::SURFACE_CONTENT:
         return viz::mojom::DrawQuadStateDataView::Tag::SURFACE_QUAD_STATE;
-      case cc::DrawQuad::TEXTURE_CONTENT:
+      case viz::DrawQuad::TEXTURE_CONTENT:
         return viz::mojom::DrawQuadStateDataView::Tag::TEXTURE_QUAD_STATE;
-      case cc::DrawQuad::TILED_CONTENT:
+      case viz::DrawQuad::TILED_CONTENT:
         return viz::mojom::DrawQuadStateDataView::Tag::TILE_QUAD_STATE;
-      case cc::DrawQuad::YUV_VIDEO_CONTENT:
+      case viz::DrawQuad::YUV_VIDEO_CONTENT:
         return viz::mojom::DrawQuadStateDataView::Tag::YUV_VIDEO_QUAD_STATE;
     }
     NOTREACHED();
     return viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE;
   }
 
-  static const cc::DrawQuad& debug_border_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& debug_border_quad_state(
+      const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& render_pass_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& render_pass_quad_state(
+      const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& solid_color_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& solid_color_quad_state(
+      const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& surface_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& surface_quad_state(const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& texture_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& texture_quad_state(const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& tile_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& tile_quad_state(const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& stream_video_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& stream_video_quad_state(
+      const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static const cc::DrawQuad& yuv_video_quad_state(const cc::DrawQuad& quad) {
+  static const viz::DrawQuad& yuv_video_quad_state(const viz::DrawQuad& quad) {
     return quad;
   }
 
-  static bool Read(viz::mojom::DrawQuadStateDataView data, cc::DrawQuad* out) {
+  static bool Read(viz::mojom::DrawQuadStateDataView data, viz::DrawQuad* out) {
     switch (data.tag()) {
       case viz::mojom::DrawQuadStateDataView::Tag::DEBUG_BORDER_QUAD_STATE:
         return data.ReadDebugBorderQuadState(out);
@@ -117,113 +121,113 @@
 };
 
 template <>
-struct StructTraits<viz::mojom::DebugBorderQuadStateDataView, cc::DrawQuad> {
-  static uint32_t color(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::DebugBorderQuadStateDataView, viz::DrawQuad> {
+  static uint32_t color(const viz::DrawQuad& input) {
     const cc::DebugBorderDrawQuad* quad =
         cc::DebugBorderDrawQuad::MaterialCast(&input);
     return quad->color;
   }
 
-  static int32_t width(const cc::DrawQuad& input) {
+  static int32_t width(const viz::DrawQuad& input) {
     const cc::DebugBorderDrawQuad* quad =
         cc::DebugBorderDrawQuad::MaterialCast(&input);
     return quad->width;
   }
 
   static bool Read(viz::mojom::DebugBorderQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
-struct StructTraits<viz::mojom::RenderPassQuadStateDataView, cc::DrawQuad> {
-  static int32_t render_pass_id(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::RenderPassQuadStateDataView, viz::DrawQuad> {
+  static int32_t render_pass_id(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     DCHECK(quad->render_pass_id);
     return quad->render_pass_id;
   }
 
-  static uint32_t mask_resource_id(const cc::DrawQuad& input) {
+  static uint32_t mask_resource_id(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->mask_resource_id();
   }
 
-  static const gfx::RectF& mask_uv_rect(const cc::DrawQuad& input) {
+  static const gfx::RectF& mask_uv_rect(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->mask_uv_rect;
   }
 
-  static const gfx::Size& mask_texture_size(const cc::DrawQuad& input) {
+  static const gfx::Size& mask_texture_size(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->mask_texture_size;
   }
 
-  static const gfx::Vector2dF& filters_scale(const cc::DrawQuad& input) {
+  static const gfx::Vector2dF& filters_scale(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->filters_scale;
   }
 
-  static const gfx::PointF& filters_origin(const cc::DrawQuad& input) {
+  static const gfx::PointF& filters_origin(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->filters_origin;
   }
 
-  static const gfx::RectF& tex_coord_rect(const cc::DrawQuad& input) {
+  static const gfx::RectF& tex_coord_rect(const viz::DrawQuad& input) {
     const cc::RenderPassDrawQuad* quad =
         cc::RenderPassDrawQuad::MaterialCast(&input);
     return quad->tex_coord_rect;
   }
 
   static bool Read(viz::mojom::RenderPassQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
-struct StructTraits<viz::mojom::SolidColorQuadStateDataView, cc::DrawQuad> {
-  static uint32_t color(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::SolidColorQuadStateDataView, viz::DrawQuad> {
+  static uint32_t color(const viz::DrawQuad& input) {
     const cc::SolidColorDrawQuad* quad =
         cc::SolidColorDrawQuad::MaterialCast(&input);
     return quad->color;
   }
 
-  static bool force_anti_aliasing_off(const cc::DrawQuad& input) {
+  static bool force_anti_aliasing_off(const viz::DrawQuad& input) {
     const cc::SolidColorDrawQuad* quad =
         cc::SolidColorDrawQuad::MaterialCast(&input);
     return quad->force_anti_aliasing_off;
   }
 
   static bool Read(viz::mojom::SolidColorQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
-struct StructTraits<viz::mojom::StreamVideoQuadStateDataView, cc::DrawQuad> {
-  static uint32_t resource_id(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::StreamVideoQuadStateDataView, viz::DrawQuad> {
+  static uint32_t resource_id(const viz::DrawQuad& input) {
     const cc::StreamVideoDrawQuad* quad =
         cc::StreamVideoDrawQuad::MaterialCast(&input);
     return quad->resources.ids[cc::StreamVideoDrawQuad::kResourceIdIndex];
   }
 
-  static const gfx::Size& resource_size_in_pixels(const cc::DrawQuad& input) {
+  static const gfx::Size& resource_size_in_pixels(const viz::DrawQuad& input) {
     const cc::StreamVideoDrawQuad* quad =
         cc::StreamVideoDrawQuad::MaterialCast(&input);
     return quad->overlay_resources
         .size_in_pixels[cc::StreamVideoDrawQuad::kResourceIdIndex];
   }
 
-  static const gfx::Transform& matrix(const cc::DrawQuad& input) {
+  static const gfx::Transform& matrix(const viz::DrawQuad& input) {
     const cc::StreamVideoDrawQuad* quad =
         cc::StreamVideoDrawQuad::MaterialCast(&input);
     return quad->matrix;
   }
 
   static bool Read(viz::mojom::StreamVideoQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
@@ -234,106 +238,106 @@
                         cc::SurfaceDrawQuadType* out);
 };
 template <>
-struct StructTraits<viz::mojom::SurfaceQuadStateDataView, cc::DrawQuad> {
-  static const viz::SurfaceId& surface(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::SurfaceQuadStateDataView, viz::DrawQuad> {
+  static const viz::SurfaceId& surface(const viz::DrawQuad& input) {
     const cc::SurfaceDrawQuad* quad = cc::SurfaceDrawQuad::MaterialCast(&input);
     return quad->surface_id;
   }
 
   static cc::SurfaceDrawQuadType surface_draw_quad_type(
-      const cc::DrawQuad& input) {
+      const viz::DrawQuad& input) {
     const cc::SurfaceDrawQuad* quad = cc::SurfaceDrawQuad::MaterialCast(&input);
     return quad->surface_draw_quad_type;
   }
 
   static bool Read(viz::mojom::SurfaceQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
-struct StructTraits<viz::mojom::TextureQuadStateDataView, cc::DrawQuad> {
-  static uint32_t resource_id(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::TextureQuadStateDataView, viz::DrawQuad> {
+  static uint32_t resource_id(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->resource_id();
   }
 
-  static const gfx::Size& resource_size_in_pixels(const cc::DrawQuad& input) {
+  static const gfx::Size& resource_size_in_pixels(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->resource_size_in_pixels();
   }
 
-  static bool premultiplied_alpha(const cc::DrawQuad& input) {
+  static bool premultiplied_alpha(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->premultiplied_alpha;
   }
 
-  static const gfx::PointF& uv_top_left(const cc::DrawQuad& input) {
+  static const gfx::PointF& uv_top_left(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->uv_top_left;
   }
 
-  static const gfx::PointF& uv_bottom_right(const cc::DrawQuad& input) {
+  static const gfx::PointF& uv_bottom_right(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->uv_bottom_right;
   }
 
-  static uint32_t background_color(const cc::DrawQuad& input) {
+  static uint32_t background_color(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->background_color;
   }
 
-  static base::span<const float> vertex_opacity(const cc::DrawQuad& input) {
+  static base::span<const float> vertex_opacity(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->vertex_opacity;
   }
 
-  static bool y_flipped(const cc::DrawQuad& input) {
+  static bool y_flipped(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->y_flipped;
   }
 
-  static bool nearest_neighbor(const cc::DrawQuad& input) {
+  static bool nearest_neighbor(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->nearest_neighbor;
   }
 
-  static bool secure_output_only(const cc::DrawQuad& input) {
+  static bool secure_output_only(const viz::DrawQuad& input) {
     const cc::TextureDrawQuad* quad = cc::TextureDrawQuad::MaterialCast(&input);
     return quad->secure_output_only;
   }
 
   static bool Read(viz::mojom::TextureQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 template <>
-struct StructTraits<viz::mojom::TileQuadStateDataView, cc::DrawQuad> {
-  static const gfx::RectF& tex_coord_rect(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::TileQuadStateDataView, viz::DrawQuad> {
+  static const gfx::RectF& tex_coord_rect(const viz::DrawQuad& input) {
     const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input);
     return quad->tex_coord_rect;
   }
 
-  static const gfx::Size& texture_size(const cc::DrawQuad& input) {
+  static const gfx::Size& texture_size(const viz::DrawQuad& input) {
     const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input);
     return quad->texture_size;
   }
 
-  static bool swizzle_contents(const cc::DrawQuad& input) {
+  static bool swizzle_contents(const viz::DrawQuad& input) {
     const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input);
     return quad->swizzle_contents;
   }
 
-  static bool nearest_neighbor(const cc::DrawQuad& input) {
+  static bool nearest_neighbor(const viz::DrawQuad& input) {
     const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input);
     return quad->nearest_neighbor;
   }
 
-  static uint32_t resource_id(const cc::DrawQuad& input) {
+  static uint32_t resource_id(const viz::DrawQuad& input) {
     const cc::TileDrawQuad* quad = cc::TileDrawQuad::MaterialCast(&input);
     return quad->resource_id();
   }
 
-  static bool Read(viz::mojom::TileQuadStateDataView data, cc::DrawQuad* out);
+  static bool Read(viz::mojom::TileQuadStateDataView data, viz::DrawQuad* out);
 };
 
 template <>
@@ -345,96 +349,96 @@
 };
 
 template <>
-struct StructTraits<viz::mojom::YUVVideoQuadStateDataView, cc::DrawQuad> {
-  static const gfx::RectF& ya_tex_coord_rect(const cc::DrawQuad& input) {
+struct StructTraits<viz::mojom::YUVVideoQuadStateDataView, viz::DrawQuad> {
+  static const gfx::RectF& ya_tex_coord_rect(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->ya_tex_coord_rect;
   }
 
-  static const gfx::RectF& uv_tex_coord_rect(const cc::DrawQuad& input) {
+  static const gfx::RectF& uv_tex_coord_rect(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->uv_tex_coord_rect;
   }
 
-  static const gfx::Size& ya_tex_size(const cc::DrawQuad& input) {
+  static const gfx::Size& ya_tex_size(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->ya_tex_size;
   }
 
-  static const gfx::Size& uv_tex_size(const cc::DrawQuad& input) {
+  static const gfx::Size& uv_tex_size(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->uv_tex_size;
   }
 
-  static uint32_t y_plane_resource_id(const cc::DrawQuad& input) {
+  static uint32_t y_plane_resource_id(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->y_plane_resource_id();
   }
 
-  static uint32_t u_plane_resource_id(const cc::DrawQuad& input) {
+  static uint32_t u_plane_resource_id(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->u_plane_resource_id();
   }
 
-  static uint32_t v_plane_resource_id(const cc::DrawQuad& input) {
+  static uint32_t v_plane_resource_id(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->v_plane_resource_id();
   }
 
-  static uint32_t a_plane_resource_id(const cc::DrawQuad& input) {
+  static uint32_t a_plane_resource_id(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->a_plane_resource_id();
   }
 
   static cc::YUVVideoDrawQuad::ColorSpace color_space(
-      const cc::DrawQuad& input) {
+      const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->color_space;
   }
 
-  static float resource_offset(const cc::DrawQuad& input) {
+  static float resource_offset(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->resource_offset;
   }
 
-  static float resource_multiplier(const cc::DrawQuad& input) {
+  static float resource_multiplier(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->resource_multiplier;
   }
 
-  static uint32_t bits_per_channel(const cc::DrawQuad& input) {
+  static uint32_t bits_per_channel(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->bits_per_channel;
   }
-  static gfx::ColorSpace video_color_space(const cc::DrawQuad& input) {
+  static gfx::ColorSpace video_color_space(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->video_color_space;
   }
-  static bool require_overlay(const cc::DrawQuad& input) {
+  static bool require_overlay(const viz::DrawQuad& input) {
     const cc::YUVVideoDrawQuad* quad =
         cc::YUVVideoDrawQuad::MaterialCast(&input);
     return quad->require_overlay;
   }
 
   static bool Read(viz::mojom::YUVVideoQuadStateDataView data,
-                   cc::DrawQuad* out);
+                   viz::DrawQuad* out);
 };
 
 struct DrawQuadWithSharedQuadState {
-  const cc::DrawQuad* quad;
+  const viz::DrawQuad* quad;
   const viz::SharedQuadState* shared_quad_state;
 };
 
@@ -457,7 +461,7 @@
     return {input.shared_quad_state};
   }
 
-  static const cc::DrawQuad& draw_quad_state(
+  static const viz::DrawQuad& draw_quad_state(
       const DrawQuadWithSharedQuadState& input) {
     return *input.quad;
   }
@@ -465,8 +469,8 @@
 
 // This StructTraits is only used for deserialization within RenderPasses.
 template <>
-struct StructTraits<viz::mojom::DrawQuadDataView, cc::DrawQuad> {
-  static bool Read(viz::mojom::DrawQuadDataView data, cc::DrawQuad* out);
+struct StructTraits<viz::mojom::DrawQuadDataView, viz::DrawQuad> {
+  static bool Read(viz::mojom::DrawQuadDataView data, viz::DrawQuad* out);
 };
 
 template <>
diff --git a/services/viz/public/cpp/compositing/render_pass.typemap b/services/viz/public/cpp/compositing/render_pass.typemap
index a0ac18b..f20d23db4 100644
--- a/services/viz/public/cpp/compositing/render_pass.typemap
+++ b/services/viz/public/cpp/compositing/render_pass.typemap
@@ -4,7 +4,7 @@
 
 mojom = "//services/viz/public/interfaces/compositing/render_pass.mojom"
 public_headers = [
-  "//cc/quads/draw_quad.h",
+  "//components/viz/common/quads/draw_quad.h",
   "//cc/quads/render_pass.h",
 ]
 traits_headers = [
diff --git a/services/viz/public/cpp/compositing/render_pass_struct_traits.cc b/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
index 729db3f..a7dbc13 100644
--- a/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
+++ b/services/viz/public/cpp/compositing/render_pass_struct_traits.cc
@@ -38,14 +38,14 @@
   mojo::ArrayDataView<viz::mojom::DrawQuadDataView> quads;
   data.GetQuadListDataView(&quads);
   viz::SharedQuadState* last_sqs = nullptr;
-  cc::DrawQuad* last_draw_quad = nullptr;
+  viz::DrawQuad* last_draw_quad = nullptr;
   for (size_t i = 0; i < quads.size(); ++i) {
     viz::mojom::DrawQuadDataView quad_data_view;
     quads.GetDataView(i, &quad_data_view);
     viz::mojom::DrawQuadStateDataView quad_state_data_view;
     quad_data_view.GetDrawQuadStateDataView(&quad_state_data_view);
 
-    cc::DrawQuad* quad =
+    viz::DrawQuad* quad =
         AllocateAndConstruct(quad_state_data_view.tag(), &(*out)->quad_list);
     if (!quad)
       return false;
@@ -68,14 +68,14 @@
 
     // If this quad is a fallback SurfaceDrawQuad then update the previous
     // primary SurfaceDrawQuad to point to this quad.
-    if (quad->material == cc::DrawQuad::SURFACE_CONTENT) {
+    if (quad->material == viz::DrawQuad::SURFACE_CONTENT) {
       const cc::SurfaceDrawQuad* surface_draw_quad =
           cc::SurfaceDrawQuad::MaterialCast(quad);
       if (surface_draw_quad->surface_draw_quad_type ==
           cc::SurfaceDrawQuadType::FALLBACK) {
         // A fallback quad must immediately follow a primary SurfaceDrawQuad.
         if (!last_draw_quad ||
-            last_draw_quad->material != cc::DrawQuad::SURFACE_CONTENT) {
+            last_draw_quad->material != viz::DrawQuad::SURFACE_CONTENT) {
           return false;
         }
         cc::SurfaceDrawQuad* last_surface_draw_quad =
diff --git a/services/viz/public/cpp/compositing/struct_traits_unittest.cc b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
index de34f9a..a87ead5d 100644
--- a/services/viz/public/cpp/compositing/struct_traits_unittest.cc
+++ b/services/viz/public/cpp/compositing/struct_traits_unittest.cc
@@ -6,8 +6,7 @@
 
 #include "base/message_loop/message_loop.h"
 #include "base/test/scoped_task_environment.h"
-#include "cc/ipc/copy_output_result_struct_traits.h"
-#include "cc/ipc/texture_mailbox_struct_traits.h"
+#include "build/build_config.h"
 #include "cc/output/compositor_frame.h"
 #include "cc/quads/debug_border_draw_quad.h"
 #include "cc/quads/render_pass.h"
@@ -29,6 +28,7 @@
 #include "services/viz/public/cpp/compositing/compositor_frame_metadata_struct_traits.h"
 #include "services/viz/public/cpp/compositing/compositor_frame_struct_traits.h"
 #include "services/viz/public/cpp/compositing/copy_output_request_struct_traits.h"
+#include "services/viz/public/cpp/compositing/copy_output_result_struct_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operation_struct_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operations_struct_traits.h"
 #include "services/viz/public/cpp/compositing/frame_sink_id_struct_traits.h"
@@ -41,6 +41,7 @@
 #include "services/viz/public/cpp/compositing/surface_id_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_info_struct_traits.h"
 #include "services/viz/public/cpp/compositing/surface_sequence_struct_traits.h"
+#include "services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h"
 #include "services/viz/public/cpp/compositing/transferable_resource_struct_traits.h"
 #include "services/viz/public/interfaces/compositing/begin_frame_args.mojom.h"
 #include "services/viz/public/interfaces/compositing/compositor_frame.mojom.h"
@@ -1123,7 +1124,7 @@
   std::unique_ptr<cc::RenderPass> render_pass = cc::RenderPass::Create();
   render_pass->SetNew(1, gfx::Rect(), gfx::Rect(), gfx::Transform());
 
-  const cc::DrawQuad::Material material = cc::DrawQuad::YUV_VIDEO_CONTENT;
+  const DrawQuad::Material material = DrawQuad::YUV_VIDEO_CONTENT;
   const gfx::Rect rect(1234, 4321, 1357, 7531);
   const gfx::Rect opaque_rect(1357, 8642, 432, 123);
   const gfx::Rect visible_rect(1337, 7331, 561, 293);
@@ -1178,4 +1179,148 @@
   EXPECT_EQ(bits_per_channel, out_quad->bits_per_channel);
   EXPECT_EQ(require_overlay, out_quad->require_overlay);
 }
+
+TEST_F(StructTraitsTest, CopyOutputResult_Empty) {
+  auto input = std::make_unique<CopyOutputResult>(
+      CopyOutputResult::Format::RGBA_BITMAP, gfx::Rect());
+  std::unique_ptr<CopyOutputResult> output;
+  SerializeAndDeserialize<mojom::CopyOutputResult>(std::move(input), &output);
+
+  EXPECT_TRUE(output->IsEmpty());
+  EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_BITMAP);
+  EXPECT_TRUE(output->rect().IsEmpty());
+  EXPECT_FALSE(output->AsSkBitmap().readyToDraw());
+  EXPECT_EQ(output->GetTextureMailbox(), nullptr);
+}
+
+TEST_F(StructTraitsTest, CopyOutputResult_Bitmap) {
+  const gfx::Rect result_rect(42, 43, 7, 8);
+  SkBitmap bitmap;
+  const sk_sp<SkColorSpace> adobe_rgb = SkColorSpace::MakeRGB(
+      SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kAdobeRGB_Gamut);
+  bitmap.allocN32Pixels(7, 8, adobe_rgb);
+  bitmap.eraseARGB(123, 213, 77, 33);
+  std::unique_ptr<CopyOutputResult> input =
+      std::make_unique<CopyOutputSkBitmapResult>(result_rect, bitmap);
+
+  std::unique_ptr<CopyOutputResult> output;
+  SerializeAndDeserialize<mojom::CopyOutputResult>(std::move(input), &output);
+
+  EXPECT_FALSE(output->IsEmpty());
+  EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_BITMAP);
+  EXPECT_EQ(output->rect(), result_rect);
+  EXPECT_EQ(output->GetTextureMailbox(), nullptr);
+
+  const SkBitmap& out_bitmap = output->AsSkBitmap();
+  EXPECT_TRUE(out_bitmap.readyToDraw());
+  EXPECT_EQ(out_bitmap.width(), result_rect.width());
+  EXPECT_EQ(out_bitmap.height(), result_rect.height());
+
+  // Check that the pixels are the same as the input and the color spaces are
+  // equivalent.
+  SkBitmap expected_bitmap;
+  expected_bitmap.allocN32Pixels(7, 8, adobe_rgb);
+  expected_bitmap.eraseARGB(123, 213, 77, 33);
+  EXPECT_EQ(expected_bitmap.getSize(), out_bitmap.getSize());
+  EXPECT_EQ(0, std::memcmp(expected_bitmap.getPixels(), out_bitmap.getPixels(),
+                           expected_bitmap.getSize()));
+  EXPECT_TRUE(SkColorSpace::Equals(expected_bitmap.colorSpace(),
+                                   out_bitmap.colorSpace()));
+}
+
+TEST_F(StructTraitsTest, CopyOutputResult_Texture) {
+  base::test::ScopedTaskEnvironment scoped_task_environment;
+
+  const gfx::Rect result_rect(12, 34, 56, 78);
+  const int8_t mailbox_name[GL_MAILBOX_SIZE_CHROMIUM] = {
+      0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 9, 7, 5, 3, 1, 3};
+  const uint32_t target = 3;
+  gpu::SyncToken sync_token(gpu::CommandBufferNamespace::GPU_IO, 0,
+                            gpu::CommandBufferId::FromUnsafeValue(0x123),
+                            71234838);
+  base::RunLoop run_loop;
+  auto callback = SingleReleaseCallback::Create(base::Bind(
+      [](base::Closure quit_closure, const gpu::SyncToken& expected_sync_token,
+         const gpu::SyncToken& sync_token, bool is_lost) {
+        EXPECT_EQ(expected_sync_token, sync_token);
+        EXPECT_TRUE(is_lost);
+        quit_closure.Run();
+      },
+      run_loop.QuitClosure(), sync_token));
+  gpu::Mailbox mailbox;
+  mailbox.SetName(mailbox_name);
+  TextureMailbox texture_mailbox(mailbox, gpu::SyncToken(), target);
+  std::unique_ptr<CopyOutputResult> input =
+      std::make_unique<CopyOutputTextureResult>(result_rect, texture_mailbox,
+                                                std::move(callback));
+
+  std::unique_ptr<CopyOutputResult> output;
+  SerializeAndDeserialize<mojom::CopyOutputResult>(std::move(input), &output);
+
+  EXPECT_FALSE(output->IsEmpty());
+  EXPECT_EQ(output->format(), CopyOutputResult::Format::RGBA_TEXTURE);
+  EXPECT_EQ(output->rect(), result_rect);
+  ASSERT_NE(output->GetTextureMailbox(), nullptr);
+  EXPECT_EQ(output->GetTextureMailbox()->mailbox(), mailbox);
+
+  std::unique_ptr<SingleReleaseCallback> out_callback =
+      output->TakeTextureOwnership();
+  out_callback->Run(sync_token, true /* is_lost */);
+  // If the CopyOutputResult callback is called (which is the intended
+  // behaviour), this will exit. Otherwise, this test will time out and fail.
+  run_loop.Run();
+}
+
+TEST_F(StructTraitsTest, TextureMailbox) {
+  const int8_t mailbox_name[GL_MAILBOX_SIZE_CHROMIUM] = {
+      0, 9, 8, 7, 6, 5, 4, 3, 2, 1, 9, 7, 5, 3, 1, 2};
+  const gpu::CommandBufferNamespace command_buffer_namespace = gpu::IN_PROCESS;
+  const int32_t extra_data_field = 0xbeefbeef;
+  const gpu::CommandBufferId command_buffer_id(
+      gpu::CommandBufferId::FromUnsafeValue(0xdeadbeef));
+  const uint64_t release_count = 0xdeadbeefdeadL;
+  const gpu::SyncToken sync_token(command_buffer_namespace, extra_data_field,
+                                  command_buffer_id, release_count);
+  const uint32_t texture_target = 1337;
+  const gfx::Size size_in_pixels(93, 24);
+  const bool is_overlay_candidate = true;
+  const bool secure_output_only = true;
+  const bool nearest_neighbor = true;
+  const gfx::ColorSpace color_space = gfx::ColorSpace(
+      gfx::ColorSpace::PrimaryID::BT470M, gfx::ColorSpace::TransferID::GAMMA28,
+      gfx::ColorSpace::MatrixID::BT2020_NCL, gfx::ColorSpace::RangeID::LIMITED);
+#if defined(OS_ANDROID)
+  const bool is_backed_by_surface_texture = true;
+  const bool wants_promotion_hint = true;
+#endif
+
+  gpu::Mailbox mailbox;
+  mailbox.SetName(mailbox_name);
+  TextureMailbox input(mailbox, sync_token, texture_target, size_in_pixels,
+                       is_overlay_candidate, secure_output_only);
+  input.set_nearest_neighbor(nearest_neighbor);
+  input.set_color_space(color_space);
+#if defined(OS_ANDROID)
+  input.set_is_backed_by_surface_texture(is_backed_by_surface_texture);
+  input.set_wants_promotion_hint(wants_promotion_hint);
+#endif
+
+  TextureMailbox output;
+  SerializeAndDeserialize<mojom::TextureMailbox>(input, &output);
+
+  EXPECT_EQ(mailbox, output.mailbox());
+  EXPECT_EQ(sync_token, output.sync_token());
+  EXPECT_EQ(texture_target, output.target());
+  EXPECT_EQ(size_in_pixels, output.size_in_pixels());
+  EXPECT_EQ(is_overlay_candidate, output.is_overlay_candidate());
+  EXPECT_EQ(secure_output_only, output.secure_output_only());
+  EXPECT_EQ(nearest_neighbor, output.nearest_neighbor());
+  EXPECT_EQ(color_space, output.color_space());
+#if defined(OS_ANDROID)
+  EXPECT_EQ(is_backed_by_surface_texture,
+            output.is_backed_by_surface_texture());
+  EXPECT_EQ(wants_promotion_hint, output.wants_promotion_hint());
+#endif
+}
+
 }  // namespace viz
diff --git a/services/viz/public/cpp/compositing/texture_mailbox.typemap b/services/viz/public/cpp/compositing/texture_mailbox.typemap
new file mode 100644
index 0000000..e02ba31
--- /dev/null
+++ b/services/viz/public/cpp/compositing/texture_mailbox.typemap
@@ -0,0 +1,12 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//services/viz/public/interfaces/compositing/texture_mailbox.mojom"
+public_headers = [ "//components/viz/common/quads/texture_mailbox.h" ]
+traits_headers =
+    [ "//services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h" ]
+deps = [
+  "//components/viz/common",
+]
+type_mappings = [ "viz.mojom.TextureMailbox=viz::TextureMailbox" ]
diff --git a/cc/ipc/texture_mailbox_struct_traits.h b/services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h
similarity index 80%
rename from cc/ipc/texture_mailbox_struct_traits.h
rename to services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h
index 9f10322..6e1a9e12 100644
--- a/cc/ipc/texture_mailbox_struct_traits.h
+++ b/services/viz/public/cpp/compositing/texture_mailbox_struct_traits.h
@@ -2,19 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CC_IPC_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
-#define CC_IPC_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
+#ifndef SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
+#define SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
 
-#include "cc/ipc/texture_mailbox.mojom-shared.h"
+#include "build/build_config.h"
 #include "components/viz/common/quads/texture_mailbox.h"
 #include "gpu/ipc/common/mailbox_holder_struct_traits.h"
+#include "services/viz/public/interfaces/compositing/texture_mailbox.mojom-shared.h"
 #include "ui/gfx/geometry/mojo/geometry_struct_traits.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
 
 namespace mojo {
 
 template <>
-struct StructTraits<cc::mojom::TextureMailboxDataView, viz::TextureMailbox> {
+struct StructTraits<viz::mojom::TextureMailboxDataView, viz::TextureMailbox> {
   static const gpu::MailboxHolder& mailbox_holder(
       const viz::TextureMailbox& input) {
     return input.mailbox_holder_;
@@ -56,7 +57,7 @@
     return input.color_space_;
   }
 
-  static bool Read(cc::mojom::TextureMailboxDataView data,
+  static bool Read(viz::mojom::TextureMailboxDataView data,
                    viz::TextureMailbox* out) {
 #if defined(OS_ANDROID)
     out->is_backed_by_surface_texture_ = data.is_backed_by_surface_texture();
@@ -74,4 +75,4 @@
 
 }  // namespace mojo
 
-#endif  // CC_IPC_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
+#endif  // SERVICES_VIZ_PUBLIC_CPP_COMPOSITING_TEXTURE_MAILBOX_STRUCT_TRAITS_H_
diff --git a/services/viz/public/cpp/compositing/typemaps.gni b/services/viz/public/cpp/compositing/typemaps.gni
index c897a68..02ad7222 100644
--- a/services/viz/public/cpp/compositing/typemaps.gni
+++ b/services/viz/public/cpp/compositing/typemaps.gni
@@ -9,6 +9,7 @@
   "//services/viz/public/cpp/compositing/filter_operation.typemap",
   "//services/viz/public/cpp/compositing/filter_operations.typemap",
   "//services/viz/public/cpp/compositing/copy_output_request.typemap",
+  "//services/viz/public/cpp/compositing/copy_output_result.typemap",
   "//services/viz/public/cpp/compositing/frame_sink_id.typemap",
   "//services/viz/public/cpp/compositing/local_surface_id.typemap",
   "//services/viz/public/cpp/compositing/render_pass.typemap",
@@ -20,4 +21,5 @@
   "//services/viz/public/cpp/compositing/surface_id.typemap",
   "//services/viz/public/cpp/compositing/surface_info.typemap",
   "//services/viz/public/cpp/compositing/transferable_resource.typemap",
+  "//services/viz/public/cpp/compositing/texture_mailbox.typemap",
 ]
diff --git a/services/viz/public/interfaces/BUILD.gn b/services/viz/public/interfaces/BUILD.gn
index 8b98c26..046330c8 100644
--- a/services/viz/public/interfaces/BUILD.gn
+++ b/services/viz/public/interfaces/BUILD.gn
@@ -11,6 +11,7 @@
     "compositing/compositor_frame_metadata.mojom",
     "compositing/compositor_frame_sink.mojom",
     "compositing/copy_output_request.mojom",
+    "compositing/copy_output_result.mojom",
     "compositing/filter_operation.mojom",
     "compositing/filter_operations.mojom",
     "compositing/frame_sink_id.mojom",
@@ -25,12 +26,13 @@
     "compositing/surface_id.mojom",
     "compositing/surface_info.mojom",
     "compositing/surface_sequence.mojom",
+    "compositing/texture_mailbox.mojom",
+    "compositing/texture_mailbox_releaser.mojom",
     "compositing/transferable_resource.mojom",
     "hit_test/hit_test_region_list.mojom",
   ]
 
   public_deps = [
-    "//cc/ipc:interfaces",
     "//gpu/ipc/common:interfaces",
     "//mojo/common:common_custom_types",
     "//skia/public/interfaces",
diff --git a/services/viz/public/interfaces/compositing/copy_output_request.mojom b/services/viz/public/interfaces/compositing/copy_output_request.mojom
index 9a862db..af8e9bc 100644
--- a/services/viz/public/interfaces/compositing/copy_output_request.mojom
+++ b/services/viz/public/interfaces/compositing/copy_output_request.mojom
@@ -4,21 +4,21 @@
 
 module viz.mojom;
 
-import "cc/ipc/copy_output_result.mojom";
-import "cc/ipc/texture_mailbox.mojom";
+import "services/viz/public/interfaces/compositing/copy_output_result.mojom";
+import "services/viz/public/interfaces/compositing/texture_mailbox.mojom";
 import "mojo/common/unguessable_token.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
 // See components/viz/common/quads/copy_output_request.h.
 struct CopyOutputRequest {
-  cc.mojom.CopyOutputResultFormat result_format;
+  CopyOutputResultFormat result_format;
 
   mojo.common.mojom.UnguessableToken? source;
   gfx.mojom.Rect? area;
 
   // DEPRECATED: To be removed once tab capture is moved into VIZ.
   // http://crbug.com/754872
-  cc.mojom.TextureMailbox? texture_mailbox;
+  TextureMailbox? texture_mailbox;
 
   CopyOutputResultSender result_sender;
 };
@@ -26,5 +26,5 @@
 // When the display compositor is ready to respond to the CopyOutputRequest,
 // it uses this interface to send back the result.
 interface CopyOutputResultSender {
-  SendResult(cc.mojom.CopyOutputResult result);
+  SendResult(CopyOutputResult result);
 };
diff --git a/cc/ipc/copy_output_result.mojom b/services/viz/public/interfaces/compositing/copy_output_result.mojom
similarity index 77%
rename from cc/ipc/copy_output_result.mojom
rename to services/viz/public/interfaces/compositing/copy_output_result.mojom
index b410be7..52e2a15 100644
--- a/cc/ipc/copy_output_result.mojom
+++ b/services/viz/public/interfaces/compositing/copy_output_result.mojom
@@ -2,10 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
-import "cc/ipc/texture_mailbox.mojom";
-import "cc/ipc/texture_mailbox_releaser.mojom";
+
+import "services/viz/public/interfaces/compositing/texture_mailbox.mojom";
+import "services/viz/public/interfaces/compositing/texture_mailbox_releaser.mojom";
 import "skia/public/interfaces/bitmap.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
 
diff --git a/cc/ipc/texture_mailbox.mojom b/services/viz/public/interfaces/compositing/texture_mailbox.mojom
similarity index 96%
rename from cc/ipc/texture_mailbox.mojom
rename to services/viz/public/interfaces/compositing/texture_mailbox.mojom
index 90a92b7..39be86e 100644
--- a/cc/ipc/texture_mailbox.mojom
+++ b/services/viz/public/interfaces/compositing/texture_mailbox.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
 import "gpu/ipc/common/mailbox_holder.mojom";
 import "ui/gfx/geometry/mojo/geometry.mojom";
diff --git a/cc/ipc/texture_mailbox_releaser.mojom b/services/viz/public/interfaces/compositing/texture_mailbox_releaser.mojom
similarity index 95%
rename from cc/ipc/texture_mailbox_releaser.mojom
rename to services/viz/public/interfaces/compositing/texture_mailbox_releaser.mojom
index 3b9ec3c..0b6a94e 100644
--- a/cc/ipc/texture_mailbox_releaser.mojom
+++ b/services/viz/public/interfaces/compositing/texture_mailbox_releaser.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-module cc.mojom;
+module viz.mojom;
 
 import "gpu/ipc/common/sync_token.mojom";
 
diff --git a/testing/buildbot/chromium.gpu.fyi.json b/testing/buildbot/chromium.gpu.fyi.json
index 6fad4d2..2dc94f9 100644
--- a/testing/buildbot/chromium.gpu.fyi.json
+++ b/testing/buildbot/chromium.gpu.fyi.json
@@ -3149,19 +3149,6 @@
         },
         "test": "angle_unittests",
         "use_xvfb": false
-      },
-      {
-        "swarming": {
-          "can_use_on_swarming_builders": false,
-          "dimension_sets": [
-            {
-              "gpu": "8086:1912",
-              "os": "Ubuntu"
-            }
-          ]
-        },
-        "test": "gpu_unittests",
-        "use_xvfb": false
       }
     ],
     "isolated_scripts": []
diff --git a/testing/buildbot/filters/fuchsia.content_unittests.filter b/testing/buildbot/filters/fuchsia.content_unittests.filter
index 7b369761..8734c947 100644
--- a/testing/buildbot/filters/fuchsia.content_unittests.filter
+++ b/testing/buildbot/filters/fuchsia.content_unittests.filter
@@ -78,6 +78,8 @@
 -QuotaPolicyCookieStoreTest.TestDestroyOnBackgroundThread
 -QuotaPolicyCookieStoreTest.TestPersistence
 -QuotaPolicyCookieStoreTest.TestPolicy
+-_/DOMStorageAreaParamTest.DeleteOrigin/0
+-_/DOMStorageAreaParamTest.DeleteOrigin/1
 
 # https://crbug.com/761214
 -RendererAudioOutputStreamFactoryIntegrationTest.StreamIntegrationTest
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index e248315c..06e06ad7 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3675,6 +3675,3 @@
 crbug.com/762423 [ Android ] http/tests/dom/create-contextual-fragment-from-svg-document-range.html [ Pass Crash ]
 crbug.com/762399 [ Android ] http/tests/cache/zero-length-xhr.html [ Pass Crash ]
 crbug.com/762486 [ Win7 Debug ] virtual/mojo-loading/http/tests/security/xss-DENIED-iframe-src-alias.html [ Pass Failure ]
-
-# Flaky
-crbug.com/747975 [ Mac10.12 Linux ] virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime.html [ Failure Pass ]
diff --git a/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt b/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
index cd1ef64..07ccb4bc 100644
--- a/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
+++ b/third_party/WebKit/LayoutTests/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
@@ -6,6 +6,7 @@
 EVENT(webkitfullscreenchange)
 Should keep rect on document
 handler: #document (0, 0, 800, 600)
+handler: #document (56, 600, 712, 8)
 
 END OF TEST
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/cache/resources/etag-200-empty.php b/third_party/WebKit/LayoutTests/http/tests/cache/resources/etag-200-empty.php
new file mode 100644
index 0000000..f9b013e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/cache/resources/etag-200-empty.php
@@ -0,0 +1,12 @@
+<?
+// Returns non-empty body and response headers that cause revalidation, and
+// returns 200 with empty body for revalidating requests.
+header('ETag: foo');
+header('Cache-control: max-age=0');
+
+if ($_SERVER['HTTP_IF_NONE_MATCH'] == 'foo') {
+    // The body is intentionally empty.
+    exit;
+}
+echo "/* comment */";
+?>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-css.html b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-css.html
new file mode 100644
index 0000000..8d6e698
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-css.html
@@ -0,0 +1,28 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+</head>
+<script>
+  var t_css = async_test(
+    "SRI with CSS with empty body after revalidation shouldn't crash");
+  function revalidate_css() {
+    var link = document.createElement('link');
+    link.setAttribute('rel', 'stylesheet');
+    link.integrity="sha256-YsI40D9FX0QghiYVdxQyySP2TOmARkLC5uPRO8RL2dE=";
+    link.onload = t_css.unreached_func('Second request should fail');
+    link.onerror = t_css.step_func_done();
+    link.href =
+      "../../cache/resources/etag-200-empty.php?empty-after-revalidate-css";
+    document.head.appendChild(link);
+  }
+</script>
+<link
+  href="../../cache/resources/etag-200-empty.php?empty-after-revalidate-css"
+  rel="stylesheet"
+  integrity="sha256-YsI40D9FX0QghiYVdxQyySP2TOmARkLC5uPRO8RL2dE="
+  onload="t_css.step_timeout(revalidate_css, 0)"
+  onerror="t_css.unreached_func('First request should pass')()"
+>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-script.html b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-script.html
new file mode 100644
index 0000000..eb6e489
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/subresourceIntegrity/empty-after-revalidate-script.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+</head>
+<script>
+  var t_script = async_test(
+    "SRI with script with empty body after revalidation shouldn't crash");
+  function revalidate_script() {
+    var script = document.createElement('script');
+    script.integrity = "sha256-YsI40D9FX0QghiYVdxQyySP2TOmARkLC5uPRO8RL2dE=";
+    script.onload = t_script.unreached_func('Second request should fail');
+    script.onerror = t_script.step_func_done();
+    script.src =
+      "../../cache/resources/etag-200-empty.php?empty-after-revalidate-script";
+    document.head.appendChild(script);
+  }
+</script>
+<script
+  src="../../cache/resources/etag-200-empty.php?empty-after-revalidate-script"
+  type="text/javascript"
+  integrity="sha256-YsI40D9FX0QghiYVdxQyySP2TOmARkLC5uPRO8RL2dE="
+  onload="t_script.step_timeout(revalidate_script, 0)"
+  onerror="t_script.unreached_func('First request should pass')()"
+></script>
+</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html b/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html
index 554c76fb..4c58267 100644
--- a/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html
+++ b/third_party/WebKit/LayoutTests/media/controls/closed-captions-single-track.html
@@ -36,7 +36,6 @@
 
       // Captions track should become visible after the closed caption button is pressed.
       checkCaptionsVisible(video, captions);
-      checkButtonHasClass(toggleClosedCaptionsButton(video), "visible");
 
       // Click the closed captions button again and make sure the menu does not appear.
       clickCaptionButton(video);
@@ -44,7 +43,6 @@
 
       // Captions track should become invisible after the closed caption button is pressed.
       checkCaptionsHidden(video);
-      checkButtonNotHasClass(toggleClosedCaptionsButton(video), "visible");
     }));
   });
 
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-cast.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-cast.html
deleted file mode 100644
index ee37a61..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-cast.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player state is reflected in CSS classes on the cast button.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-controls.js"></script>
-<script src="../media-file.js"></script>
-<video controls width=400></video>
-<script>
-async_test(t => {
-  var video = document.querySelector('video');
-
-  video.onloadedmetadata = t.step_func_done(function() {
-    // Pretend we have a cast device.
-    internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true);
-    checkButtonNotHasClass(castButton(video), 'on');
-
-    // Pretend we are casting.
-    internals.mediaPlayerPlayingRemotelyChanged(video, true);
-    checkButtonHasClass(castButton(video), 'on');
-  });
-
-  video.src = findMediaFile("video", "../content/counting");
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-fullscreen.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-fullscreen.html
deleted file mode 100644
index ea43064..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-fullscreen.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player state is reflected in CSS classes on the fullscreen button.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-controls.js"></script>
-<script src="../media-file.js"></script>
-<video controls width=400></video>
-<script>
-async_test(t => {
-  var video = document.querySelector('video');
-
-  video.onwebkitfullscreenchange = t.step_func_done(_ => {
-    checkButtonHasClass(fullscreenButton(video), 'fullscreen');
-  });
-
-  document.onclick = t.step_func(_ => {
-    fullscreenButton(video).click();
-  });
-
-  video.onplay = t.step_func(_ => {
-    checkButtonNotHasClass(fullscreenButton(video), 'fullscreen');
-    clickAtCoordinates(1, 1);
-  });
-
-  video.src = findMediaFile("video", "../content/counting");
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-mute.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-mute.html
deleted file mode 100644
index 368e445..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-mute.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player state is reflected in CSS classes on the mute button.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-controls.js"></script>
-<script src="../media-file.js"></script>
-<video controls width=400></video>
-<script>
-async_test(t => {
-  var video = document.querySelector('video');
-  checkButtonNotHasClass(muteButton(video), 'muted');
-
-  t.step_func(_ => {
-    video.muted = true;
-
-    setTimeout(t.step_func_done(_ => {
-      checkButtonHasClass(muteButton(video), 'muted');
-    }));
-  })();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-overlay-cast.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-overlay-cast.html
deleted file mode 100644
index 4cebf33..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-overlay-cast.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player state is reflected in CSS classes on the overlay cast button.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-controls.js"></script>
-<script src="../media-file.js"></script>
-<video controls width=400></video>
-<script>
-async_test(t => {
-  var video = document.querySelector('video');
-
-  video.onloadedmetadata = t.step_func_done(function() {
-    // Pretend we have a cast device.
-    internals.mediaPlayerRemoteRouteAvailabilityChanged(video, true);
-    checkButtonNotHasClass(overlayCastButton(video), 'on');
-
-    // Pretend we are casting.
-    internals.mediaPlayerPlayingRemotelyChanged(video, true);
-    checkButtonHasClass(overlayCastButton(video), 'on');
-  });
-
-  video.src = findMediaFile("video", "../content/counting");
-  video.play();
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-pause.html b/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-pause.html
deleted file mode 100644
index 903f2ab..0000000
--- a/third_party/WebKit/LayoutTests/media/controls/toggle-class-with-state-pause.html
+++ /dev/null
@@ -1,24 +0,0 @@
-<!DOCTYPE html>
-<html>
-<title>Test that player state is reflected in CSS classes on the play button.</title>
-<script src="../../resources/testharness.js"></script>
-<script src="../../resources/testharnessreport.js"></script>
-<script src="../media-controls.js"></script>
-<script src="../media-file.js"></script>
-<video controls width=400></video>
-<script>
-async_test(t => {
-  var video = document.querySelector('video');
-
-  video.onplay = t.step_func(_ => {
-    checkButtonNotHasClass(playButton(video), 'pause');
-    video.pause();
-  });
-
-  video.src = findMediaFile("video", "../content/counting");
-  video.play().catch(t.step_func_done(_ => {
-    checkButtonHasClass(playButton(video), 'pause');
-  }));
-});
-</script>
-</html>
diff --git a/third_party/WebKit/LayoutTests/media/media-controls.js b/third_party/WebKit/LayoutTests/media/media-controls.js
index bceaa77..2752348 100644
--- a/third_party/WebKit/LayoutTests/media/media-controls.js
+++ b/third_party/WebKit/LayoutTests/media/media-controls.js
@@ -154,18 +154,6 @@
     return false;
 }
 
-function toggleClosedCaptionsButton(videoElement) {
-    return mediaControlsButton(videoElement, 'toggle-closed-captions-button');
-}
-
-function playButton(videoElement) {
-    return mediaControlsButton(videoElement, 'play-button');
-}
-
-function muteButton(videoElement) {
-    return mediaControlsButton(videoElement, 'mute-button');
-}
-
 function clickAtCoordinates(x, y)
 {
     eventSender.mouseMoveTo(x, y);
@@ -253,11 +241,3 @@
     return computedStyle.display !== "none" &&
            computedStyle.visibility === "visible";
 }
-
-function checkButtonHasClass(button, className) {
-  assert_true(button.classList.contains(className));
-}
-
-function checkButtonNotHasClass(button, className) {
-  assert_false(button.classList.contains(className));
-}
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-mute-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/video-mute-repaint-expected.txt
deleted file mode 100644
index 8213b6e..0000000
--- a/third_party/WebKit/LayoutTests/paint/invalidation/video-mute-repaint-expected.txt
+++ /dev/null
@@ -1,91 +0,0 @@
-{
-  "layers": [
-    {
-      "name": "LayoutView #document",
-      "bounds": [800, 600],
-      "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
-    },
-    {
-      "name": "LayoutVideo VIDEO id='v'",
-      "position": [8, 8],
-      "bounds": [700, 525],
-      "drawsContent": false
-    },
-    {
-      "name": "Squashing Containment Layer",
-      "drawsContent": false
-    },
-    {
-      "name": "LayoutFlexibleBox (relative positioned) DIV",
-      "position": [8, 8],
-      "bounds": [700, 525],
-      "paintInvalidations": [
-        {
-          "object": "LayoutFlexibleBox (relative positioned) DIV",
-          "rect": [0, 0, 700, 525],
-          "reason": "geometry"
-        }
-      ]
-    },
-    {
-      "name": "Squashing Layer (first squashed layer: LayoutFlexibleBox (relative positioned) DIV)",
-      "position": [8, 8],
-      "bounds": [700, 525],
-      "paintInvalidations": [
-        {
-          "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-          "rect": [580, 508, 70, 2],
-          "reason": "disappeared"
-        },
-        {
-          "object": "LayoutFlexibleBox DIV",
-          "rect": [580, 508, 70, 2],
-          "reason": "geometry"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [632, 491, 36, 36],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [562, 491, 36, 36],
-          "reason": "full"
-        },
-        {
-          "object": "LayoutButton INPUT class='muted'",
-          "rect": [530, 493, 32, 32],
-          "reason": "full"
-        }
-      ]
-    }
-  ],
-  "objectPaintInvalidations": [
-    {
-      "object": "LayoutVideo VIDEO id='v'",
-      "reason": "style change"
-    },
-    {
-      "object": "LayoutFlexibleBox (relative positioned) DIV",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutButton INPUT class='muted'",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutFlexibleBox DIV",
-      "reason": "geometry"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-      "reason": "full"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-      "reason": "disappeared"
-    }
-  ]
-}
-
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
index e0a1f07c..2af8702 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 6558104..ca0e28f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index b9b0e5f7..b202525 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -24,27 +24,11 @@
           text run at (0,8) width 30: "/ 0:07"
     LayoutSlider {INPUT} at (108,15) size 49x2
       LayoutFlexibleBox {DIV} at (0,0) size 49x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 85x48
+          LayoutBlockFlow {DIV} at (49,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (98,142) size 85x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 85x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 49x2 [bgcolor=#DADADA]
-layer at (215,142) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 49x2 [bgcolor=#4285F4]
-layer at (165,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (48.50,0) size 0.48x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (147,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (49,-18) size 36x36
-layer at (240,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
index 3ce85890..6f1b9b4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
index 3c8b94af7..57e32b07 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,52) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,260) size 320x32 scrollHeight 34
+layer at (8,260) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,260) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,276) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,276) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,297) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,297) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,505) size 320x32 scrollHeight 34
+layer at (8,505) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,505) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,521) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,521) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,766) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,766) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
index f6b4218e..fe0d905f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.txt
index 3441439c..583daaa3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/media/media-document-audio-repaint-expected.txt
@@ -23,7 +23,7 @@
         LayoutBlockFlow {DIV} at (0,-31) size 300x32
     layer at (40,124) size 300x0
       LayoutFlexibleBox (relative positioned) {DIV} at (0,-41) size 300x0
-    layer at (40,134) size 300x32 scrollHeight 34
+    layer at (40,134) size 300x32 scrollHeight 40
       LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
         LayoutButton {INPUT} at (0,0) size 32x32
         LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -36,26 +36,10 @@
               text run at (0,8) width 30: "/ 0:01"
         LayoutSlider {INPUT} at (108,15) size 81x2
           LayoutFlexibleBox {DIV} at (0,0) size 81x2
+            LayoutBlockFlow {DIV} at (-18,-23) size 117x48
+              LayoutBlockFlow {DIV} at (40.48,0) size 36x48
         LayoutButton {INPUT} at (207,0) size 32x32
         LayoutSlider {INPUT} at (257,15) size 25x2
           LayoutFlexibleBox {DIV} at (0,0) size 25x2
-    layer at (130,150) size 117x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 117x0
-    layer at (148,149) size 81x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 81x2 [bgcolor=#DADADA]
-    layer at (279,150) size 61x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-    layer at (148,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 39.69x2 [bgcolor=#4285F4]
-    layer at (188,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (39.69,0) size 40.50x2 [bgcolor=#5A5A5A]
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-    layer at (297,149) size 0x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-    layer at (170,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (40.48,-18) size 36x36
-    layer at (304,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
+            LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+              LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
index 74218e8f..e541818 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
@@ -5,7 +5,7 @@
 
 EVENT(webkitfullscreenchange)
 Should report another rect which is not on the document
-handler: no rects
+handler: DIV (56, -8, 712, 48)
 
 END OF TEST
 
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png
index f9afb5f7..abfb363 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/full-screen-iframe-allowed-video-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-iframe-expected.png
deleted file mode 100644
index 05d935d..0000000
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-iframe-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png
index f9afb5f7..abfb363 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-controls-timeline-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png
index f9afb5f7..abfb363 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/android/fullscreen/video-scrolled-iframe-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 5bbf3efa..ca0e28f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index e6485af..b202525 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -22,29 +22,13 @@
       LayoutBlockFlow (anonymous) at (4,0) size 30x32
         LayoutText {#text} at (0,8) size 30x15
           text run at (0,8) width 30: "/ 0:07"
-    LayoutSlider {INPUT} at (114,15) size 37x2
-      LayoutFlexibleBox {DIV} at (0,0) size 37x2
+    LayoutSlider {INPUT} at (108,15) size 49x2
+      LayoutFlexibleBox {DIV} at (0,0) size 49x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 85x48
+          LayoutBlockFlow {DIV} at (49,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
-      LayoutFlexibleBox {DIV} at (6,0) size 13x2
+      LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (104,142) size 73x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 73x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (12,-1) size 49x2 [bgcolor=#DADADA]
-layer at (221,142) size 49x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 49x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (12,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 49x2 [bgcolor=#4285F4]
-layer at (165,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (48.50,0) size 0.48x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (141,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (37,-18) size 36x36
-layer at (234,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (13,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
index 3ce85890..6f1b9b4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
index 3c8b94af7..57e32b07 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,52) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,260) size 320x32 scrollHeight 34
+layer at (8,260) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,260) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,276) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,276) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,297) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,297) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,505) size 320x32 scrollHeight 34
+layer at (8,505) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,505) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,521) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,521) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,766) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,766) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png
index d144fd2..f4549b6b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.11/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png
index d144fd2..f4549b6b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-retina/media/video-zoom-controls-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
index f7da7d4..5f347be9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/video/video-controls-layer-creation-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
new file mode 100644
index 0000000..86ee642
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/mac/fullscreen/compositor-touch-hit-rects-fullscreen-video-controls-expected.txt
@@ -0,0 +1,12 @@
+This test makes sure that touch hit rects are reported for fullscreen HTML5 video control elements even when there is a document handler.
+
+Should have single rect on document before fullscreen
+handler: #document (0, 0, 800, 600)
+
+EVENT(webkitfullscreenchange)
+Should keep rect on document
+handler: #document (0, 0, 800, 600)
+handler: #document (55, 600, 713, 8)
+
+END OF TEST
+
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 1064fbb7..bb528ee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index 34ba009..5ca85b6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -24,27 +24,11 @@
           text run at (0,9) width 31: "/ 0:07"
     LayoutSlider {INPUT} at (108.05,15) size 48.95x2
       LayoutFlexibleBox {DIV} at (0,0) size 48.95x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 84.95x48
+          LayoutBlockFlow {DIV} at (48.95,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (98,142) size 85x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 84.95x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 48.95x2 [bgcolor=#DADADA]
-layer at (215,142) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 48.95x2 [bgcolor=#4285F4]
-layer at (163,141) size 2x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (46.98,0) size 1.95x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (147,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (48.95,-18) size 36x36
-layer at (240,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png
index ca1b998..68a1145d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt
index bf4ef43..657f77fa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,50) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,258) size 320x32 scrollHeight 34
+layer at (8,258) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,258) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,274) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,273) size 72x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,274) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,273) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,273) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,273) size 72x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,273) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,273) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,256) size 36x36 backgroundClip at (8,258) size 320x32 clip at (8,258) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,256) size 36x36 backgroundClip at (8,258) size 320x32 clip at (8,258) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,294) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,294) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,502) size 320x32 scrollHeight 34
+layer at (8,502) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,502) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,518) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,517) size 72x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,518) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,517) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,517) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,517) size 72x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,517) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,517) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,500) size 36x36 backgroundClip at (8,502) size 320x32 clip at (8,502) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,500) size 36x36 backgroundClip at (8,502) size 320x32 clip at (8,502) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
 layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,746) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,762) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,761) size 72x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,762) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,761) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,761) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,761) size 72x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,761) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,761) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,744) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,744) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png
index 0e8c2bd..65da69a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png
index 360ea7a..23d7968 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
index 4b71d29..92cee9c 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.txt
index 38126ca2..e9d56e2f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/media/media-document-audio-repaint-expected.txt
@@ -23,7 +23,7 @@
         LayoutBlockFlow {DIV} at (0,-31) size 300x32
     layer at (40,124) size 300x0
       LayoutFlexibleBox (relative positioned) {DIV} at (0,-41) size 300x0
-    layer at (40,134) size 300x32 scrollHeight 34
+    layer at (40,134) size 300x32 scrollHeight 40
       LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
         LayoutButton {INPUT} at (0,0) size 32x32
         LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -36,26 +36,10 @@
               text run at (0,9) width 31: "/ 0:01"
         LayoutSlider {INPUT} at (108.05,15) size 80.95x2
           LayoutFlexibleBox {DIV} at (0,0) size 80.95x2
+            LayoutBlockFlow {DIV} at (-18,-23) size 116.95x48
+              LayoutBlockFlow {DIV} at (40.47,0) size 36x48
         LayoutButton {INPUT} at (207,0) size 32x32
         LayoutSlider {INPUT} at (257,15) size 25x2
           LayoutFlexibleBox {DIV} at (0,0) size 25x2
-    layer at (130,150) size 117x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 116.95x0
-    layer at (148,149) size 81x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 80.95x2 [bgcolor=#DADADA]
-    layer at (279,150) size 61x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-    layer at (148,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 39.66x2 [bgcolor=#4285F4]
-    layer at (188,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (39.66,0) size 40.47x2 [bgcolor=#5A5A5A]
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-    layer at (297,149) size 0x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-    layer at (171,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (40.47,-18) size 36x36
-    layer at (304,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
+            LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+              LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
similarity index 68%
rename from third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
rename to third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
index 21276223..e1da66c 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-mute-repaint-expected.txt
@@ -4,7 +4,14 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow BODY",
+          "rect": [8, 8, 784, 529],
+          "reason": "geometry"
+        }
+      ]
     },
     {
       "name": "LayoutVideo VIDEO id='v'",
@@ -39,19 +46,19 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [597, 491, 36, 36],
+          "object": "LayoutSlider INPUT",
+          "rect": [580, 508, 70, 2],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [562, 491, 36, 36],
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [632, 485, 36, 48],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-          "rect": [580, 508, 35, 2],
-          "reason": "appeared"
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [562, 485, 36, 48],
+          "reason": "full"
         },
         {
           "object": "LayoutButton INPUT",
@@ -63,6 +70,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow BODY",
+      "reason": "geometry"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "geometry"
+    },
+    {
       "object": "LayoutVideo VIDEO id='v'",
       "reason": "style change"
     },
@@ -75,16 +90,16 @@
       "reason": "full"
     },
     {
+      "object": "LayoutSlider INPUT",
+      "reason": "full"
+    },
+    {
       "object": "LayoutFlexibleBox DIV",
       "reason": "geometry"
     },
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
+      "object": "LayoutBlockFlow DIV id='thumb'",
       "reason": "full"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-      "reason": "appeared"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
similarity index 68%
copy from third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
copy to third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
index 21276223..2298d2f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/video-unmute-repaint-expected.txt
@@ -4,7 +4,14 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (anonymous)",
+          "rect": [8, 8, 784, 529],
+          "reason": "geometry"
+        }
+      ]
     },
     {
       "name": "LayoutVideo VIDEO id='v'",
@@ -39,19 +46,19 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [597, 491, 36, 36],
+          "object": "LayoutSlider INPUT",
+          "rect": [580, 508, 70, 2],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [562, 491, 36, 36],
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [597, 485, 36, 48],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-          "rect": [580, 508, 35, 2],
-          "reason": "appeared"
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [562, 485, 36, 48],
+          "reason": "full"
         },
         {
           "object": "LayoutButton INPUT",
@@ -63,6 +70,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow (anonymous)",
+      "reason": "geometry"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "geometry"
+    },
+    {
       "object": "LayoutVideo VIDEO id='v'",
       "reason": "style change"
     },
@@ -75,16 +90,16 @@
       "reason": "full"
     },
     {
+      "object": "LayoutSlider INPUT",
+      "reason": "full"
+    },
+    {
       "object": "LayoutFlexibleBox DIV",
       "reason": "geometry"
     },
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
+      "object": "LayoutBlockFlow DIV id='thumb'",
       "reason": "full"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-      "reason": "appeared"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 1064fbb7..bb528ee 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index fe3d357..5ca85b6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -24,27 +24,11 @@
           text run at (0,9) width 31: "/ 0:07"
     LayoutSlider {INPUT} at (108.05,15) size 48.95x2
       LayoutFlexibleBox {DIV} at (0,0) size 48.95x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 84.95x48
+          LayoutBlockFlow {DIV} at (48.95,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (98,142) size 85x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 84.95x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 48.95x2 [bgcolor=#DADADA]
-layer at (215,142) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 48.95x2 [bgcolor=#4285F4]
-layer at (164,141) size 2x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (47.48,0) size 1.45x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (147,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (48.95,-18) size 36x36
-layer at (240,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
index ca1b998..68a1145d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
index bf4ef43..657f77fa 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,50) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,258) size 320x32 scrollHeight 34
+layer at (8,258) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,258) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,274) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,273) size 72x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,274) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,273) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,273) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,273) size 72x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,273) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,273) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,256) size 36x36 backgroundClip at (8,258) size 320x32 clip at (8,258) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,256) size 36x36 backgroundClip at (8,258) size 320x32 clip at (8,258) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,294) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,294) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,502) size 320x32 scrollHeight 34
+layer at (8,502) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,502) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,518) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,517) size 72x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,518) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,517) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,517) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,517) size 72x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,517) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,517) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,500) size 36x36 backgroundClip at (8,502) size 320x32 clip at (8,502) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,500) size 36x36 backgroundClip at (8,502) size 320x32 clip at (8,502) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,538) size 320x240
 layer at (8,538) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,538) size 320x198 backgroundClip at (8,538) size 320x62 clip at (8,538) size 320x62
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,746) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 23.36x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,9) width 24: "0:00"
     LayoutSlider {INPUT} at (73.36,15) size 71.64x2
       LayoutFlexibleBox {DIV} at (0,0) size 71.64x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107.64x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,746) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (63,762) size 108x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107.64x0
-layer at (81,761) size 72x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71.64x2 [bgcolor=#DADADA]
-layer at (203,762) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,761) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (81,761) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (81,761) size 72x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71.64x2 [bgcolor=#5A5A5A]
-layer at (221,761) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,761) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (63,744) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,744) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
index 0e8c2bd..65da69a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-dark-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
index 360ea7a..23d7968 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/virtual/new-remote-playback-pipeline/media/controls/video-overlay-cast-light-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 7c9ef09..6ad8a86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index af258bc..b202525 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -24,27 +24,11 @@
           text run at (0,8) width 30: "/ 0:07"
     LayoutSlider {INPUT} at (108,15) size 49x2
       LayoutFlexibleBox {DIV} at (0,0) size 49x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 85x48
+          LayoutBlockFlow {DIV} at (49,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (98,142) size 85x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 85x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 49x2 [bgcolor=#DADADA]
-layer at (215,142) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 49x2 [bgcolor=#4285F4]
-layer at (163,141) size 2x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (47.03,0) size 1.95x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (147,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (49,-18) size 36x36
-layer at (240,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png
index 5ba393f..d2f382e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt
index 7085bc7..f443612f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,52) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,260) size 320x32 scrollHeight 34
+layer at (8,260) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,260) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,276) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,276) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,297) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,297) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,505) size 320x32 scrollHeight 34
+layer at (8,505) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,505) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,521) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,521) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,766) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,766) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
index e723f9c2..1b193a5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.txt
index 848fc39..a779023 100644
--- a/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/media/media-document-audio-repaint-expected.txt
@@ -23,7 +23,7 @@
         LayoutBlockFlow {DIV} at (0,-31) size 300x32
     layer at (40,124) size 300x0
       LayoutFlexibleBox (relative positioned) {DIV} at (0,-41) size 300x0
-    layer at (40,134) size 300x32 scrollHeight 34
+    layer at (40,134) size 300x32 scrollHeight 40
       LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
         LayoutButton {INPUT} at (0,0) size 32x32
         LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -36,26 +36,10 @@
               text run at (0,8) width 30: "/ 0:01"
         LayoutSlider {INPUT} at (108,15) size 81x2
           LayoutFlexibleBox {DIV} at (0,0) size 81x2
+            LayoutBlockFlow {DIV} at (-18,-23) size 117x48
+              LayoutBlockFlow {DIV} at (40.48,0) size 36x48
         LayoutButton {INPUT} at (207,0) size 32x32
         LayoutSlider {INPUT} at (257,15) size 25x2
           LayoutFlexibleBox {DIV} at (0,0) size 25x2
-    layer at (130,150) size 117x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 117x0
-    layer at (148,149) size 81x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 81x2 [bgcolor=#DADADA]
-    layer at (279,150) size 61x0
-      LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-    layer at (148,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 39.69x2 [bgcolor=#4285F4]
-    layer at (188,149) size 40x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (39.69,0) size 40.50x2 [bgcolor=#5A5A5A]
-    layer at (297,149) size 25x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-    layer at (297,149) size 0x2
-      LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-    layer at (170,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (40.48,-18) size 36x36
-    layer at (304,132) size 36x36 backgroundClip at (40,134) size 300x32 clip at (40,134) size 300x32
-      LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
+            LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+              LayoutBlockFlow {DIV} at (25,0) size 36x48
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
similarity index 68%
copy from third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
index 21276223..fde2ac0 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-mute-repaint-expected.txt
@@ -4,7 +4,14 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow BODY",
+          "rect": [8, 8, 784, 530],
+          "reason": "geometry"
+        }
+      ]
     },
     {
       "name": "LayoutVideo VIDEO id='v'",
@@ -39,19 +46,19 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [597, 491, 36, 36],
+          "object": "LayoutSlider INPUT",
+          "rect": [580, 508, 70, 2],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [562, 491, 36, 36],
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [632, 485, 36, 48],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-          "rect": [580, 508, 35, 2],
-          "reason": "appeared"
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [562, 485, 36, 48],
+          "reason": "full"
         },
         {
           "object": "LayoutButton INPUT",
@@ -63,6 +70,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow BODY",
+      "reason": "geometry"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "geometry"
+    },
+    {
       "object": "LayoutVideo VIDEO id='v'",
       "reason": "style change"
     },
@@ -75,16 +90,16 @@
       "reason": "full"
     },
     {
+      "object": "LayoutSlider INPUT",
+      "reason": "full"
+    },
+    {
       "object": "LayoutFlexibleBox DIV",
       "reason": "geometry"
     },
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
+      "object": "LayoutBlockFlow DIV id='thumb'",
       "reason": "full"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-      "reason": "appeared"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
similarity index 68%
copy from third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
copy to third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
index 21276223..10eb59f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/video-unmute-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/video-unmute-repaint-expected.txt
@@ -4,7 +4,14 @@
       "name": "LayoutView #document",
       "bounds": [800, 600],
       "contentsOpaque": true,
-      "backgroundColor": "#FFFFFF"
+      "backgroundColor": "#FFFFFF",
+      "paintInvalidations": [
+        {
+          "object": "LayoutBlockFlow (anonymous)",
+          "rect": [8, 8, 784, 530],
+          "reason": "geometry"
+        }
+      ]
     },
     {
       "name": "LayoutVideo VIDEO id='v'",
@@ -39,19 +46,19 @@
           "reason": "geometry"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [597, 491, 36, 36],
+          "object": "LayoutSlider INPUT",
+          "rect": [580, 508, 70, 2],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
-          "rect": [562, 491, 36, 36],
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [597, 485, 36, 48],
           "reason": "full"
         },
         {
-          "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-          "rect": [580, 508, 35, 2],
-          "reason": "appeared"
+          "object": "LayoutBlockFlow DIV id='thumb'",
+          "rect": [562, 485, 36, 48],
+          "reason": "full"
         },
         {
           "object": "LayoutButton INPUT",
@@ -63,6 +70,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutBlockFlow (anonymous)",
+      "reason": "geometry"
+    },
+    {
+      "object": "RootInlineBox",
+      "reason": "geometry"
+    },
+    {
       "object": "LayoutVideo VIDEO id='v'",
       "reason": "style change"
     },
@@ -75,16 +90,16 @@
       "reason": "full"
     },
     {
+      "object": "LayoutSlider INPUT",
+      "reason": "full"
+    },
+    {
       "object": "LayoutFlexibleBox DIV",
       "reason": "geometry"
     },
     {
-      "object": "LayoutBlockFlow (positioned) DIV id='thumb'",
+      "object": "LayoutBlockFlow DIV id='thumb'",
       "reason": "full"
-    },
-    {
-      "object": "LayoutBlockFlow (positioned) DIV class='-internal-track-segment-highlight-before'",
-      "reason": "appeared"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
index 7c9ef09..6ad8a86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
index b9b0e5f7..b202525 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.txt
@@ -11,7 +11,7 @@
     LayoutBlockFlow {DIV} at (0,118) size 300x32
 layer at (8,8) size 300x108
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x108
-layer at (8,126) size 300x32 scrollHeight 34
+layer at (8,126) size 300x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 300x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -24,27 +24,11 @@
           text run at (0,8) width 30: "/ 0:07"
     LayoutSlider {INPUT} at (108,15) size 49x2
       LayoutFlexibleBox {DIV} at (0,0) size 49x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 85x48
+          LayoutBlockFlow {DIV} at (49,0) size 36x48
     LayoutButton {INPUT} at (175,0) size 32x32
     LayoutSlider {INPUT} at (225,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (268,0) size 32x32
-layer at (98,142) size 85x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 85x0
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 49x2 [bgcolor=#DADADA]
-layer at (215,142) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (116,141) size 49x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 49x2 [bgcolor=#4285F4]
-layer at (165,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (48.50,0) size 0.48x2 [bgcolor=#5A5A5A]
-layer at (233,141) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (233,141) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (147,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (49,-18) size 36x36
-layer at (240,124) size 36x36 backgroundClip at (8,126) size 300x32 clip at (8,126) size 300x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
index 5ba393f..d2f382e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
index 7085bc7..f443612f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/virtual/new-remote-playback-pipeline/media/controls/video-controls-with-cast-rendering-expected.txt
@@ -20,7 +20,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,52) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,260) size 320x32 scrollHeight 34
+layer at (8,260) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -29,38 +29,22 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,260) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,276) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,276) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,275) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,275) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,275) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,258) size 36x36 backgroundClip at (8,260) size 320x32 clip at (8,260) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,297) size 320x240
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x240
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,297) size 320x198
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,505) size 320x32 scrollHeight 34
+layer at (8,505) size 320x32 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -69,32 +53,16 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,505) size 32x32
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,521) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,521) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,520) size 71x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,520) size 25x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,520) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,503) size 36x36 backgroundClip at (8,505) size 320x32 clip at (8,505) size 320x32
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
   LayoutVideo (positioned) {VIDEO} at (8,542) size 320x240
 layer at (8,542) size 320x240 backgroundClip at (0,0) size 785x600 clip at (0,0) size 785x600
@@ -102,7 +70,7 @@
     LayoutBlockFlow {DIV} at (0,208) size 320x32
 layer at (8,542) size 320x198 backgroundClip at (8,542) size 320x58 clip at (8,542) size 320x58
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x198
-layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 34
+layer at (8,750) size 320x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0 scrollHeight 40
   LayoutFlexibleBox (relative positioned) {DIV} at (0,0) size 320x32 [bgcolor=#FAFAFA]
     LayoutButton {INPUT} at (0,0) size 32x32
     LayoutFlexibleBox {DIV} at (32,0) size 24x32 [color=#5A5A5A]
@@ -111,29 +79,13 @@
           text run at (0,8) width 24: "0:00"
     LayoutSlider {INPUT} at (74,15) size 71x2
       LayoutFlexibleBox {DIV} at (0,0) size 71x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 107x48
+          LayoutBlockFlow {DIV} at (0,0) size 36x48
     LayoutButton {INPUT} at (163,0) size 32x32
     LayoutSlider {INPUT} at (213,15) size 25x2
       LayoutFlexibleBox {DIV} at (0,0) size 25x2
+        LayoutBlockFlow {DIV} at (-18,-23) size 61x48
+          LayoutBlockFlow {DIV} at (25,0) size 36x48
     LayoutButton {INPUT} at (288,0) size 32x32
 layer at (264,750) size 32x32 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
   LayoutButton {INPUT} at (256,0) size 32x32
-layer at (64,766) size 107x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 107x0
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 71x2 [bgcolor=#DADADA]
-layer at (203,766) size 61x0
-  LayoutBlockFlow (relative positioned) {DIV} at (-18,1) size 61x0
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) {DIV} at (18,-1) size 25x2 [bgcolor=#DADADA]
-layer at (82,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#4285F4]
-layer at (82,765) size 71x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 71x2 [bgcolor=#5A5A5A]
-layer at (221,765) size 25x2 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 25x2 [bgcolor=#4285F4]
-layer at (221,765) size 0x2
-  LayoutBlockFlow (positioned) zI: 1 {DIV} at (0,0) size 0x2 [bgcolor=#5A5A5A]
-layer at (64,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (0,-18) size 36x36
-layer at (228,748) size 36x36 backgroundClip at (0,0) size 0x0 clip at (0,0) size 0x0
-  LayoutBlockFlow (positioned) zI: 2 {DIV} at (25,-18) size 36x36
diff --git a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png b/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
deleted file mode 100644
index 6ad8a86..0000000
--- a/third_party/WebKit/LayoutTests/platform/win7/virtual/mojo-loading/http/tests/media/video-buffered-range-contains-currentTime-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/decode-gif.html b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-gif.html
new file mode 100644
index 0000000..33009a6
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-gif.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script src="../resources/runner.js"></script>
+    <script src="resources/image_decoder_runner.js"></script>
+    <script>
+      runImageDecoderPerfTests("../../../../chrome/test/data/image_decoding/droids.gif", "Measures performance of gif decoding.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/decode-jpeg.html b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-jpeg.html
new file mode 100644
index 0000000..5a0ce9e
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-jpeg.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script src="../resources/runner.js"></script>
+    <script src="resources/image_decoder_runner.js"></script>
+    <script>
+      runImageDecoderPerfTests("../../../../chrome/test/data/image_decoding/droids.jpg", "Measures performance of jpeg decoding.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossless-webp.html b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossless-webp.html
new file mode 100644
index 0000000..dad7020
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossless-webp.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script src="../resources/runner.js"></script>
+    <script src="resources/image_decoder_runner.js"></script>
+    <script>
+      runImageDecoderPerfTests("../../../../chrome/test/data/image_decoding/droids.loss-less.webp", "Measures performance of lossless webp decoding.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossy-webp.html b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossy-webp.html
new file mode 100644
index 0000000..13fe876
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-lossy-webp.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script src="../resources/runner.js"></script>
+    <script src="resources/image_decoder_runner.js"></script>
+    <script>
+      runImageDecoderPerfTests("../../../../chrome/test/data/image_decoding/droids.webp", "Measures performance of lossy webp decoding.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/decode-png.html b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-png.html
new file mode 100644
index 0000000..2a6ea54
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/decode-png.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <script src="../resources/runner.js"></script>
+    <script src="resources/image_decoder_runner.js"></script>
+    <script>
+      runImageDecoderPerfTests("../../../../chrome/test/data/image_decoding/droids.png", "Measures performance of png decoding.");
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/PerformanceTests/ImageDecoder/resources/image_decoder_runner.js b/third_party/WebKit/PerformanceTests/ImageDecoder/resources/image_decoder_runner.js
new file mode 100644
index 0000000..8b987ec
--- /dev/null
+++ b/third_party/WebKit/PerformanceTests/ImageDecoder/resources/image_decoder_runner.js
@@ -0,0 +1,44 @@
+function runImageDecoderPerfTests(imageFile, testDescription) {
+  var isDone = false;
+
+  function runTest() {
+    var image = new Image();
+
+    // When all the data is available...
+    image.onload = function() {
+      PerfTestRunner.addRunTestStartMarker();
+      var startTime = PerfTestRunner.now();
+
+      // Issue a decode command
+      image.decode().then(function () {
+        PerfTestRunner.measureValueAsync(PerfTestRunner.now() - startTime);
+        PerfTestRunner.addRunTestEndMarker();
+
+        // addRunTestEndMarker sets isDone to true once all iterations are
+        // performed.
+        if (!isDone) {
+          runTest();
+        }
+      });
+    }
+
+    // Begin fetching the data
+    image.src = imageFile + "?" + Math.random();
+  }
+
+  window.onload = function () {
+    PerfTestRunner.startMeasureValuesAsync({
+      unit: "ms",
+      done: function () {
+        isDone = true;
+      },
+      run: function () {
+        runTest();
+      },
+      iterationCount: 20,
+      description: testDescription,
+      tracingCategories: 'blink',
+      traceEventsToMeasure: ['ImageFrameGenerator::decode'],
+    });
+  };
+}
diff --git a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
index 1e8b5d1..fc4dc4f0 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPosition.cpp
@@ -340,6 +340,18 @@
       LocalToInvalidationBackingPoint(edge_bottom_in_layer, nullptr);
 }
 
+LayoutPoint RenderedPosition::GetSamplePointForVisibility(
+    const LayoutPoint& edge_top_in_layer,
+    const LayoutPoint& edge_bottom_in_layer) {
+  FloatSize diff(edge_top_in_layer - edge_bottom_in_layer);
+  // Adjust by ~1px to avoid integer snapping error. This logic is the same
+  // as that in ComputeViewportSelectionBound in cc.
+  diff.Scale(1 / diff.DiagonalLength());
+  LayoutPoint sample_point = edge_bottom_in_layer;
+  sample_point.Move(LayoutSize(diff));
+  return sample_point;
+}
+
 bool RenderedPosition::IsVisible(bool selection_start) {
   if (IsNull())
     return false;
@@ -358,14 +370,16 @@
     return true;
 
   LayoutPoint edge_top_in_layer;
-  LayoutPoint ignored1;
+  LayoutPoint edge_bottom_in_layer;
   bool ignored2;
-  GetLocalSelectionEndpoints(selection_start, edge_top_in_layer, ignored1,
-                             ignored2);
+  GetLocalSelectionEndpoints(selection_start, edge_top_in_layer,
+                             edge_bottom_in_layer, ignored2);
+  LayoutPoint sample_point =
+      GetSamplePointForVisibility(edge_top_in_layer, edge_bottom_in_layer);
 
   LayoutBox* text_control_object = ToLayoutBox(layout_object);
   LayoutPoint position_in_input(layout_object_->LocalToAncestorPoint(
-      FloatPoint(edge_top_in_layer), text_control_object,
+      FloatPoint(sample_point), text_control_object,
       kTraverseDocumentBoundaries));
   if (!text_control_object->BorderBoxRect().Contains(position_in_input))
     return false;
diff --git a/third_party/WebKit/Source/core/editing/RenderedPosition.h b/third_party/WebKit/Source/core/editing/RenderedPosition.h
index 909a4da5..60a1533 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPosition.h
+++ b/third_party/WebKit/Source/core/editing/RenderedPosition.h
@@ -117,6 +117,10 @@
       const LayoutPoint& local_point,
       GraphicsLayer** graphics_layer_backing) const;
 
+  static LayoutPoint GetSamplePointForVisibility(
+      const LayoutPoint& edge_top_in_layer,
+      const LayoutPoint& edge_bottom_in_layer);
+
   LayoutObject* layout_object_;
   InlineBox* inline_box_;
   int offset_;
@@ -128,6 +132,8 @@
 
   mutable InlineBox* prev_leaf_child_;
   mutable InlineBox* next_leaf_child_;
+
+  FRIEND_TEST_ALL_PREFIXES(RenderedPositionTest, GetSamplePointForVisibility);
 };
 
 inline RenderedPosition::RenderedPosition()
diff --git a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
index 960cf2fc..3b5bb31 100644
--- a/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
+++ b/third_party/WebKit/Source/core/editing/RenderedPositionTest.cpp
@@ -14,7 +14,6 @@
 class RenderedPositionTest : public EditingTestBase {};
 
 #if defined(OS_ANDROID)
-// Failing on WebKit Android (Nexus4): https://crbug.com/752827
 #define MAYBE_IsVisible DISABLED_IsVisible
 #else
 #define MAYBE_IsVisible IsVisible
@@ -40,4 +39,11 @@
   EXPECT_FALSE(rendered_hidden_position.IsVisible(true));
 }
 
+TEST_F(RenderedPositionTest, GetSamplePointForVisibility) {
+  LayoutPoint top(-1, 10);
+  LayoutPoint bottom(20, 10);
+  EXPECT_EQ(LayoutPoint(19, 10),
+            RenderedPosition::GetSamplePointForVisibility(top, bottom));
+}
+
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
index b7aeaf0..b2fea87e 100644
--- a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
+++ b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.cpp
@@ -247,13 +247,15 @@
       page_->GetChromeClient().SetNeedsLowLatencyInput(frame,
                                                        has_active_handlers);
     // Fall through.
+    case kTouchAction:
     case kTouchStartOrMoveEventBlocking:
     case kTouchStartOrMoveEventPassive:
     case kPointerEvent:
       page_->GetChromeClient().SetEventListenerProperties(
           frame, WebEventListenerClass::kTouchStartOrMove,
           GetWebEventListenerProperties(
-              HasEventHandlers(kTouchStartOrMoveEventBlocking) ||
+              HasEventHandlers(kTouchAction) ||
+                  HasEventHandlers(kTouchStartOrMoveEventBlocking) ||
                   HasEventHandlers(kTouchStartOrMoveEventBlockingLowLatency),
               HasEventHandlers(kTouchStartOrMoveEventPassive) ||
                   HasEventHandlers(kPointerEvent)));
@@ -281,7 +283,8 @@
   ScrollingCoordinator* scrolling_coordinator =
       page_->GetScrollingCoordinator();
   if (scrolling_coordinator &&
-      (handler_class == kTouchStartOrMoveEventBlocking ||
+      (handler_class == kTouchAction ||
+       handler_class == kTouchStartOrMoveEventBlocking ||
        handler_class == kTouchStartOrMoveEventBlockingLowLatency)) {
     scrolling_coordinator->TouchEventTargetRectsDidChange();
   }
diff --git a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h
index 4d48831..960d64f 100644
--- a/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h
+++ b/third_party/WebKit/Source/core/frame/EventHandlerRegistry.h
@@ -32,6 +32,7 @@
     kScrollEvent,
     kWheelEventBlocking,
     kWheelEventPassive,
+    kTouchAction,
     kTouchStartOrMoveEventBlocking,
     kTouchStartOrMoveEventBlockingLowLatency,
     kTouchStartOrMoveEventPassive,
diff --git a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
index b553cf3..5091084 100644
--- a/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/LocalFrameView.cpp
@@ -1227,6 +1227,11 @@
         if (v_mode == kScrollbarAuto) {
           // This causes a vertical scrollbar to appear.
           SetVerticalScrollbarMode(kScrollbarAlwaysOn);
+          if (RuntimeEnabledFeatures::RootLayerScrollingEnabled()) {
+            GetLayoutView()
+                ->GetScrollableArea()
+                ->ForceVerticalScrollbarForFirstLayout();
+          }
         }
         // Set the initial hMode to AlwaysOff if we're auto.
         if (h_mode == kScrollbarAuto) {
@@ -5092,6 +5097,8 @@
   bool has_handlers =
       frame_->GetPage() &&
       (frame_->GetPage()->GetEventHandlerRegistry().HasEventHandlers(
+           EventHandlerRegistry::kTouchAction) ||
+       frame_->GetPage()->GetEventHandlerRegistry().HasEventHandlers(
            EventHandlerRegistry::kTouchStartOrMoveEventBlocking) ||
        frame_->GetPage()->GetEventHandlerRegistry().HasEventHandlers(
            EventHandlerRegistry::kTouchStartOrMoveEventBlockingLowLatency));
diff --git a/third_party/WebKit/Source/core/layout/BUILD.gn b/third_party/WebKit/Source/core/layout/BUILD.gn
index 3fd7dd0..30c48ff 100644
--- a/third_party/WebKit/Source/core/layout/BUILD.gn
+++ b/third_party/WebKit/Source/core/layout/BUILD.gn
@@ -421,6 +421,8 @@
     "ng/ng_out_of_flow_positioned_descendant.h",
     "ng/ng_physical_box_fragment.cc",
     "ng/ng_physical_box_fragment.h",
+    "ng/ng_physical_container_fragment.cc",
+    "ng/ng_physical_container_fragment.h",
     "ng/ng_physical_fragment.cc",
     "ng/ng_physical_fragment.h",
     "ng/ng_positioned_float.cc",
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.cpp b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
index 4d100d1..1bd661a 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.cpp
@@ -959,13 +959,17 @@
          Style()->Resize() != EResize::kNone;
 }
 
-void LayoutBox::AddLayerHitTestRects(LayerHitTestRects& layer_rects,
-                                     const PaintLayer* current_layer,
-                                     const LayoutPoint& layer_offset,
-                                     const LayoutRect& container_rect) const {
+void LayoutBox::AddLayerHitTestRects(
+    LayerHitTestRects& layer_rects,
+    const PaintLayer* current_layer,
+    const LayoutPoint& layer_offset,
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   LayoutPoint adjusted_layer_offset = layer_offset + LocationOffset();
   LayoutBoxModelObject::AddLayerHitTestRects(
-      layer_rects, current_layer, adjusted_layer_offset, container_rect);
+      layer_rects, current_layer, adjusted_layer_offset, supported_fast_actions,
+      container_rect, container_whitelisted_touch_action);
 }
 
 void LayoutBox::ComputeSelfHitTestRects(Vector<LayoutRect>& rects,
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h
index aedfaa83..17982947 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBox.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -1450,10 +1450,13 @@
                                const HitTestLocation& location_in_container,
                                const LayoutPoint& accumulated_offset,
                                HitTestAction);
-  void AddLayerHitTestRects(LayerHitTestRects&,
-                            const PaintLayer* current_composited_layer,
-                            const LayoutPoint& layer_offset,
-                            const LayoutRect& container_rect) const override;
+  void AddLayerHitTestRects(
+      LayerHitTestRects&,
+      const PaintLayer* current_composited_layer,
+      const LayoutPoint& layer_offset,
+      TouchAction supported_fast_actions,
+      const LayoutRect& container_rect,
+      TouchAction container_whitelisted_touch_action) const override;
   void ComputeSelfHitTestRects(Vector<LayoutRect>&,
                                const LayoutPoint& layer_offset) const override;
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
index 47021076..82251fa 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -500,23 +500,27 @@
     LayerHitTestRects& rects,
     const PaintLayer* current_layer,
     const LayoutPoint& layer_offset,
-    const LayoutRect& container_rect) const {
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   if (HasLayer()) {
     if (IsLayoutView()) {
       // LayoutView is handled with a special fast-path, but it needs to know
       // the current layer.
       LayoutObject::AddLayerHitTestRects(rects, Layer(), LayoutPoint(),
-                                         LayoutRect());
+                                         supported_fast_actions, LayoutRect(),
+                                         TouchAction::kTouchActionAuto);
     } else {
       // Since a LayoutObject never lives outside it's container Layer, we can
       // switch to marking entire layers instead. This may sometimes mark more
       // than necessary (when a layer is made of disjoint objects) but in
       // practice is a significant performance savings.
-      Layer()->AddLayerHitTestRects(rects);
+      Layer()->AddLayerHitTestRects(rects, supported_fast_actions);
     }
   } else {
     LayoutObject::AddLayerHitTestRects(rects, current_layer, layer_offset,
-                                       container_rect);
+                                       supported_fast_actions, container_rect,
+                                       container_whitelisted_touch_action);
   }
 }
 
@@ -1166,15 +1170,16 @@
 }
 
 void LayoutBoxModelObject::ComputeLayerHitTestRects(
-    LayerHitTestRects& rects) const {
-  LayoutObject::ComputeLayerHitTestRects(rects);
+    LayerHitTestRects& rects,
+    TouchAction supported_fast_actions) const {
+  LayoutObject::ComputeLayerHitTestRects(rects, supported_fast_actions);
 
   // If there is a continuation then we need to consult it here, since this is
   // the root of the tree walk and it wouldn't otherwise get picked up.
   // Continuations should always be siblings in the tree, so any others should
   // get picked up already by the tree walk.
   if (Continuation())
-    Continuation()->ComputeLayerHitTestRects(rects);
+    Continuation()->ComputeLayerHitTestRects(rects, supported_fast_actions);
 }
 
 LayoutRect LayoutBoxModelObject::LocalCaretRectForEmptyElement(
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
index 7c28256..e29dd5e9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.h
@@ -420,7 +420,7 @@
   void ContentChanged(ContentChangeType);
   bool HasAcceleratedCompositing() const;
 
-  void ComputeLayerHitTestRects(LayerHitTestRects&) const override;
+  void ComputeLayerHitTestRects(LayerHitTestRects&, TouchAction) const override;
 
   // Returns true if the background is painted opaque in the given rect.
   // The query rect is given in local coordinate system.
@@ -487,7 +487,9 @@
   void AddLayerHitTestRects(LayerHitTestRects&,
                             const PaintLayer*,
                             const LayoutPoint&,
-                            const LayoutRect&) const override;
+                            TouchAction,
+                            const LayoutRect&,
+                            TouchAction) const override;
 
   void StyleWillChange(StyleDifference,
                        const ComputedStyle& new_style) override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
index 1f8bab76..b657d2f 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1723,7 +1723,6 @@
   //
   // Since a CSS property cannot be applied directly to a text node, a
   // handler will have already been added for its parent so ignore it.
-  // TODO: Remove this blocking event handler; crbug.com/318381
   TouchAction old_touch_action =
       style_ ? style_->GetTouchAction() : TouchAction::kTouchActionAuto;
   if (GetNode() && !GetNode()->IsTextNode() &&
@@ -1731,12 +1730,13 @@
           (new_style.GetTouchAction() == TouchAction::kTouchActionAuto)) {
     EventHandlerRegistry& registry =
         GetDocument().GetPage()->GetEventHandlerRegistry();
-    if (new_style.GetTouchAction() != TouchAction::kTouchActionAuto)
-      registry.DidAddEventHandler(
-          *GetNode(), EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
-    else
-      registry.DidRemoveEventHandler(
-          *GetNode(), EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
+    if (new_style.GetTouchAction() != TouchAction::kTouchActionAuto) {
+      registry.DidAddEventHandler(*GetNode(),
+                                  EventHandlerRegistry::kTouchAction);
+    } else {
+      registry.DidRemoveEventHandler(*GetNode(),
+                                     EventHandlerRegistry::kTouchAction);
+    }
   }
 }
 
@@ -2335,7 +2335,8 @@
 }
 
 void LayoutObject::ComputeLayerHitTestRects(
-    LayerHitTestRects& layer_rects) const {
+    LayerHitTestRects& layer_rects,
+    TouchAction supported_fast_actions) const {
   // Figure out what layer our container is in. Any offset (or new layer) for
   // this layoutObject within it's container will be applied in
   // addLayerHitTestRects.
@@ -2361,14 +2362,17 @@
   }
 
   this->AddLayerHitTestRects(layer_rects, current_layer, layer_offset,
-                             LayoutRect());
+                             supported_fast_actions, LayoutRect(),
+                             TouchAction::kTouchActionAuto);
 }
 
 void LayoutObject::AddLayerHitTestRects(
     LayerHitTestRects& layer_rects,
     const PaintLayer* current_layer,
     const LayoutPoint& layer_offset,
-    const LayoutRect& container_rect) const {
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   DCHECK(current_layer);
   DCHECK_EQ(current_layer, this->EnclosingLayer());
 
@@ -2377,6 +2381,8 @@
   // but this seems slightly simpler.
   Vector<LayoutRect> own_rects;
   LayoutRect new_container_rect;
+  TouchAction new_container_whitelisted_touch_action =
+      TouchAction::kTouchActionAuto;
   ComputeSelfHitTestRects(own_rects, layer_offset);
 
   // When we get to have a lot of rects on a layer, the performance cost of
@@ -2387,28 +2393,40 @@
   const size_t kMaxRectsPerLayer = 100;
 
   LayerHitTestRects::iterator iter = layer_rects.find(current_layer);
-  Vector<LayoutRect>* iter_value;
-  if (iter == layer_rects.end())
-    iter_value = &layer_rects.insert(current_layer, Vector<LayoutRect>())
+  Vector<TouchActionRect>* iter_value;
+  if (iter == layer_rects.end()) {
+    iter_value = &layer_rects.insert(current_layer, Vector<TouchActionRect>())
                       .stored_value->value;
-  else
+  } else {
     iter_value = &iter->value;
+  }
+  TouchAction whitelisted_touch_action =
+      Style()->GetEffectiveTouchAction() & supported_fast_actions;
   for (size_t i = 0; i < own_rects.size(); i++) {
-    if (!container_rect.Contains(own_rects[i])) {
-      iter_value->push_back(own_rects[i]);
+    // If we have a different touch action than the container the rect needs to
+    // be reported even if it is contained.
+    if (whitelisted_touch_action != container_whitelisted_touch_action ||
+        !container_rect.Contains(own_rects[i])) {
+      iter_value->push_back(
+          TouchActionRect(own_rects[i], whitelisted_touch_action));
       if (iter_value->size() > kMaxRectsPerLayer) {
         // Just mark the entire layer instead, and switch to walking the layer
         // tree instead of the layout tree.
         layer_rects.erase(current_layer);
-        current_layer->AddLayerHitTestRects(layer_rects);
+        current_layer->AddLayerHitTestRects(layer_rects,
+                                            supported_fast_actions);
         return;
       }
-      if (new_container_rect.IsEmpty())
+      if (new_container_rect.IsEmpty()) {
+        new_container_whitelisted_touch_action = whitelisted_touch_action;
         new_container_rect = own_rects[i];
+      }
     }
   }
-  if (new_container_rect.IsEmpty())
+  if (new_container_rect.IsEmpty()) {
+    new_container_whitelisted_touch_action = container_whitelisted_touch_action;
     new_container_rect = container_rect;
+  }
 
   // If it's possible for children to have rects outside our bounds, then we
   // need to descend into the children and compute them.
@@ -2422,7 +2440,8 @@
     for (LayoutObject* curr = SlowFirstChild(); curr;
          curr = curr->NextSibling()) {
       curr->AddLayerHitTestRects(layer_rects, current_layer, layer_offset,
-                                 new_container_rect);
+                                 supported_fast_actions, new_container_rect,
+                                 new_container_whitelisted_touch_action);
     }
   }
 }
@@ -2560,12 +2579,11 @@
       style_->GetTouchAction() != TouchAction::kTouchActionAuto) {
     EventHandlerRegistry& registry =
         GetDocument().GetPage()->GetEventHandlerRegistry();
-    if (registry
-            .EventHandlerTargets(
-                EventHandlerRegistry::kTouchStartOrMoveEventBlocking)
-            ->Contains(GetNode()))
-      registry.DidRemoveEventHandler(
-          *GetNode(), EventHandlerRegistry::kTouchStartOrMoveEventBlocking);
+    if (registry.EventHandlerTargets(EventHandlerRegistry::kTouchAction)
+            ->Contains(GetNode())) {
+      registry.DidRemoveEventHandler(*GetNode(),
+                                     EventHandlerRegistry::kTouchAction);
+    }
   }
 
   SetAncestorLineBoxDirty(false);
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h
index 1c2a3d7..22eda4f570 100644
--- a/third_party/WebKit/Source/core/layout/LayoutObject.h
+++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1610,8 +1610,8 @@
   virtual IntRect AbsoluteElementBoundingBoxRect() const;
 
   // Compute a list of hit-test rectangles per layer rooted at this
-  // layoutObject.
-  virtual void ComputeLayerHitTestRects(LayerHitTestRects&) const;
+  // layoutObject with at most the given touch action.
+  virtual void ComputeLayerHitTestRects(LayerHitTestRects&, TouchAction) const;
 
   static RespectImageOrientationEnum ShouldRespectImageOrientation(
       const LayoutObject*);
@@ -1996,10 +1996,13 @@
   // containerRect is a rect that has already been added for the currentLayer
   // which is likely to be a container for child elements. Any rect wholly
   // contained by containerRect can be skipped.
-  virtual void AddLayerHitTestRects(LayerHitTestRects&,
-                                    const PaintLayer* current_layer,
-                                    const LayoutPoint& layer_offset,
-                                    const LayoutRect& container_rect) const;
+  virtual void AddLayerHitTestRects(
+      LayerHitTestRects&,
+      const PaintLayer* current_layer,
+      const LayoutPoint& layer_offset,
+      TouchAction supported_fast_actions,
+      const LayoutRect& container_rect,
+      TouchAction container_whitelisted_touch_action) const;
 
   // Add hit-test rects for this layoutObject only to the provided list.
   // layerOffset is the offset of this layoutObject within the current layer
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
index 2c9076ac..a54e6c9 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.cpp
@@ -214,15 +214,18 @@
     LayerHitTestRects& layer_rects,
     const PaintLayer* current_layer,
     const LayoutPoint& layer_offset,
-    const LayoutRect& container_rect) const {
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   LayoutPoint adjusted_layer_offset = layer_offset;
   // LayoutTableCell's location includes the offset of it's containing
   // LayoutTableRow, so we need to subtract that again here (as for
   // LayoutTableCell::offsetFromContainer.
   if (Parent())
     adjusted_layer_offset -= ParentBox()->LocationOffset();
-  LayoutBox::AddLayerHitTestRects(layer_rects, current_layer,
-                                  adjusted_layer_offset, container_rect);
+  LayoutBox::AddLayerHitTestRects(
+      layer_rects, current_layer, adjusted_layer_offset, supported_fast_actions,
+      container_rect, container_whitelisted_touch_action);
 }
 
 void LayoutTableCell::ComputeIntrinsicPadding(int collapsed_height,
diff --git a/third_party/WebKit/Source/core/layout/LayoutTableCell.h b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
index da65966..8f36586 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTableCell.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTableCell.h
@@ -345,10 +345,13 @@
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
   void ComputePreferredLogicalWidths() override;
 
-  void AddLayerHitTestRects(LayerHitTestRects&,
-                            const PaintLayer* current_composited_layer,
-                            const LayoutPoint& layer_offset,
-                            const LayoutRect& container_rect) const override;
+  void AddLayerHitTestRects(
+      LayerHitTestRects&,
+      const PaintLayer* current_composited_layer,
+      const LayoutPoint& layer_offset,
+      TouchAction supported_fast_actions,
+      const LayoutRect& container_rect,
+      TouchAction container_whitelisted_touch_action) const override;
 
   PaintInvalidationReason InvalidatePaint(
       const PaintInvalidatorContext&) const override;
diff --git a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
index a1f3ec7..3a47136 100644
--- a/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
+++ b/third_party/WebKit/Source/core/layout/LayoutTestHelper.h
@@ -115,9 +115,13 @@
     GetDocument().View()->UpdateAllLifecyclePhases();
   }
 
+  Element* GetElementById(const char* id) const {
+    return GetDocument().getElementById(id);
+  }
+
   LayoutObject* GetLayoutObjectByElementId(const char* id) const {
-    Node* node = GetDocument().getElementById(id);
-    return node ? node->GetLayoutObject() : nullptr;
+    const auto* element = GetElementById(id);
+    return element ? element->GetLayoutObject() : nullptr;
   }
 
   void LoadAhem();
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.cpp b/third_party/WebKit/Source/core/layout/LayoutText.cpp
index d906a56..994aea5 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutText.cpp
@@ -1557,10 +1557,13 @@
   return prev;
 }
 
-void LayoutText::AddLayerHitTestRects(LayerHitTestRects&,
-                                      const PaintLayer* current_layer,
-                                      const LayoutPoint& layer_offset,
-                                      const LayoutRect& container_rect) const {
+void LayoutText::AddLayerHitTestRects(
+    LayerHitTestRects&,
+    const PaintLayer* current_layer,
+    const LayoutPoint& layer_offset,
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   // Text nodes aren't event targets, so don't descend any further.
 }
 
diff --git a/third_party/WebKit/Source/core/layout/LayoutText.h b/third_party/WebKit/Source/core/layout/LayoutText.h
index b460175..4aff95c1 100644
--- a/third_party/WebKit/Source/core/layout/LayoutText.h
+++ b/third_party/WebKit/Source/core/layout/LayoutText.h
@@ -236,10 +236,13 @@
   void StyleWillChange(StyleDifference, const ComputedStyle&) final {}
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
-  void AddLayerHitTestRects(LayerHitTestRects&,
-                            const PaintLayer* current_layer,
-                            const LayoutPoint& layer_offset,
-                            const LayoutRect& container_rect) const override;
+  void AddLayerHitTestRects(
+      LayerHitTestRects&,
+      const PaintLayer* current_layer,
+      const LayoutPoint& layer_offset,
+      TouchAction supported_fast_actions,
+      const LayoutRect& container_rect,
+      TouchAction container_whitelisted_touch_action) const override;
 
   virtual InlineTextBox* CreateTextBox(
       int start,
diff --git a/third_party/WebKit/Source/core/layout/api/LayoutItem.h b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
index 1807097..2a51d8c 100644
--- a/third_party/WebKit/Source/core/layout/api/LayoutItem.h
+++ b/third_party/WebKit/Source/core/layout/api/LayoutItem.h
@@ -171,8 +171,10 @@
         ->SetShouldDoFullPaintInvalidationIncludingNonCompositingDescendants();
   }
 
-  void ComputeLayerHitTestRects(LayerHitTestRects& layer_rects) const {
-    layout_object_->ComputeLayerHitTestRects(layer_rects);
+  void ComputeLayerHitTestRects(LayerHitTestRects& layer_rects,
+                                TouchAction supported_fast_actions) const {
+    layout_object_->ComputeLayerHitTestRects(layer_rects,
+                                             supported_fast_actions);
   }
 
   FloatPoint LocalToAbsolute(const FloatPoint& local_point = FloatPoint(),
diff --git a/third_party/WebKit/Source/core/layout/ng/README.md b/third_party/WebKit/Source/core/layout/ng/README.md
index 08ea583..d7f1b273 100644
--- a/third_party/WebKit/Source/core/layout/ng/README.md
+++ b/third_party/WebKit/Source/core/layout/ng/README.md
@@ -117,13 +117,18 @@
 * Generate the coverage html from the master lcov file
 `chromium\src>C:\Perl64\bin\perl.exe dynamorio.git\third_party\lcov\genhtml output.info -o output`
 
-### Debugging ###
+### Debugging, logging and testing ###
 Both layout input node subtrees and layout output physical fragment subtrees
-may be dumped to stderr, for debugging purposes.
+may be dumped, for debugging, logging and testing purposes.
 
 #### For layout input node subtree ####
-Call NGLayoutInputNode::ShowNodeTree().
+Call NGLayoutInputNode::ShowNodeTree() to dump the tree to stderr.
 
 #### For physical fragment subtree ####
-Call NGPhysicalFragment::ShowFragmentTree(). Fragments in the subtree are not
-required to be marked as placed (i.e. know their offset).
+Call NGPhysicalFragment::ShowFragmentTree() to dump the tree to
+stderr. Fragments in the subtree are not required to be marked as placed
+(i.e. know their offset).
+
+A fragment tree may also be dumped to a String, by calling
+NGPhysicalFragment::DumpFragmentTree(). It takes a flag parameter, so that the
+output can be customized to only contain what's relevant for a given purpose.
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.cc
index efea11c..57c8d95b 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.cc
@@ -12,14 +12,13 @@
     Vector<RefPtr<NGPhysicalFragment>>& children,
     const NGLineHeightMetrics& metrics,
     RefPtr<NGBreakToken> break_token)
-    : NGPhysicalFragment(nullptr,
-                         style,
-                         size,
-                         kFragmentLineBox,
-                         std::move(break_token)),
-      metrics_(metrics) {
-  children_.swap(children);
-}
+    : NGPhysicalContainerFragment(nullptr,
+                                  style,
+                                  size,
+                                  kFragmentLineBox,
+                                  children,
+                                  std::move(break_token)),
+      metrics_(metrics) {}
 
 LayoutUnit NGPhysicalLineBoxFragment::BaselinePosition(FontBaseline) const {
   // TODO(kojii): Computing other baseline types than the used one is not
@@ -28,15 +27,4 @@
   return metrics_.ascent;
 }
 
-void NGPhysicalLineBoxFragment::UpdateVisualRect() const {
-  LayoutRect visual_rect(LayoutPoint(),
-                         LayoutSize(Size().width, Size().height));
-  for (const auto& child : children_) {
-    LayoutRect child_visual_rect = child->VisualRect();
-    child_visual_rect.Move(child->Offset().left, child->Offset().top);
-    visual_rect.Unite(child_visual_rect);
-  }
-  SetVisualRect(visual_rect);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.h
index 8d32f2f..9b8db53 100644
--- a/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/inline/ng_physical_line_box_fragment.h
@@ -7,12 +7,13 @@
 
 #include "core/CoreExport.h"
 #include "core/layout/ng/inline/ng_line_height_metrics.h"
-#include "core/layout/ng/ng_physical_fragment.h"
+#include "core/layout/ng/ng_physical_container_fragment.h"
 #include "platform/fonts/FontBaseline.h"
 
 namespace blink {
 
-class CORE_EXPORT NGPhysicalLineBoxFragment final : public NGPhysicalFragment {
+class CORE_EXPORT NGPhysicalLineBoxFragment final
+    : public NGPhysicalContainerFragment {
  public:
   // This modifies the passed-in children vector.
   NGPhysicalLineBoxFragment(const ComputedStyle&,
@@ -21,10 +22,6 @@
                             const NGLineHeightMetrics&,
                             RefPtr<NGBreakToken> break_token = nullptr);
 
-  const Vector<RefPtr<NGPhysicalFragment>>& Children() const {
-    return children_;
-  }
-
   const NGLineHeightMetrics& Metrics() const { return metrics_; }
 
   // Compute baseline for the specified baseline type.
@@ -36,12 +33,7 @@
                                                   metrics_, break_token_));
   }
 
-  // Update visual rect for this fragment.
-  void UpdateVisualRect() const override;
-
  private:
-  Vector<RefPtr<NGPhysicalFragment>> children_;
-
   NGLineHeightMetrics metrics_;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
index fcabbe27..8114bc4 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_column_layout_algorithm_test.cc
@@ -29,6 +29,28 @@
     return ToNGPhysicalBoxFragment(result->PhysicalFragment().Get());
   }
 
+  RefPtr<NGPhysicalBoxFragment> RunBlockLayoutAlgorithm(Element* element) {
+    NGBlockNode container(ToLayoutBox(element->GetLayoutObject()));
+    RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
+        kHorizontalTopBottom, TextDirection::kLtr,
+        NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
+    return RunBlockLayoutAlgorithm(*space, container);
+  }
+
+  String DumpFragmentTree(const NGPhysicalBoxFragment* fragment) {
+    NGPhysicalFragment::DumpFlags flags =
+        NGPhysicalFragment::DumpHeaderText | NGPhysicalFragment::DumpSubtree |
+        NGPhysicalFragment::DumpIndentation | NGPhysicalFragment::DumpOffset |
+        NGPhysicalFragment::DumpSize;
+
+    return fragment->DumpFragmentTree(flags);
+  }
+
+  String DumpFragmentTree(Element* element) {
+    auto fragment = RunBlockLayoutAlgorithm(element);
+    return DumpFragmentTree(fragment.Get());
+  }
+
   RefPtr<ComputedStyle> style_;
 };
 
@@ -186,52 +208,16 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(210), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(100), LayoutUnit(100)), fragment->Size());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-  // TODO(mstensho): Make this work.
-  // EXPECT_EQ(NGPhysicalSize(LayoutUnit(100), LayoutUnit(100)),
-  // column2->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child fragment in first column
-  iterator.SetParent(fragment);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-
-  // #child fragment in second column
-  iterator.SetParent(column2);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(50)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:210x100
+      offset:0,0 size:100x100
+        offset:0,0 size:75x100
+      offset:110,0 size:100x50
+        offset:0,0 size:75x50
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, BlockInThreeColumns) {
@@ -252,69 +238,18 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // first column fragment
-  iterator.SetParent(fragment);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(100), LayoutUnit(100)), fragment->Size());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-  // TODO(mstensho): Make this work.
-  // EXPECT_EQ(NGPhysicalSize(LayoutUnit(100), LayoutUnit(100)),
-  // column2->Size());
-
-  // third column fragment
-  const auto* column3 = iterator.NextChild();
-  ASSERT_TRUE(column3);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(220), LayoutUnit()), column3->Offset());
-  // TODO(mstensho): Make this work.
-  // EXPECT_EQ(NGPhysicalSize(LayoutUnit(100), LayoutUnit(100)),
-  // column3->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child fragment in first column
-  iterator.SetParent(fragment);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child fragment in second column
-  iterator.SetParent(column2);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child fragment in third column
-  iterator.SetParent(column3);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(50)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:75x100
+      offset:110,0 size:100x100
+        offset:0,0 size:75x100
+      offset:220,0 size:100x50
+        offset:0,0 size:75x50
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, ActualColumnCountGreaterThanSpecified) {
@@ -335,61 +270,18 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(210), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-
-  // third column fragment
-  const auto* column3 = iterator.NextChild();
-  ASSERT_TRUE(column3);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(220), LayoutUnit()), column3->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child fragment in first column
-  iterator.SetParent(fragment);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(1), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-
-  // #child fragment in second column
-  iterator.SetParent(column2);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(1), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-
-  // #child fragment in third column
-  iterator.SetParent(column3);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(1), LayoutUnit(50)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:210x100
+      offset:0,0 size:100x100
+        offset:0,0 size:1x100
+      offset:110,0 size:100x100
+        offset:0,0 size:1x100
+      offset:220,0 size:100x50
+        offset:0,0 size:1x50
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, TwoBlocksInTwoColumns) {
@@ -411,54 +303,17 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  // #child1 fragment in first column
-  iterator.SetParent(fragment);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(60)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  // #child2 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit(60)), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(85), LayoutUnit(40)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-
-  // #child2 fragment in second column
-  iterator.SetParent(column2);
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(85), LayoutUnit(20)), fragment->Size());
-  EXPECT_EQ(0U, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:75x60
+        offset:0,60 size:85x40
+      offset:110,0 size:100x20
+        offset:0,0 size:85x20
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, OverflowedBlock) {
@@ -483,71 +338,20 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-  // #child1 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(60)), fragment->Size());
-  FragmentChildIterator grandchild_iterator(fragment);
-  // #grandchild1 fragment in first column
-  fragment = grandchild_iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(grandchild_iterator.NextChild());
-  // #child2 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit(60)), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(85), LayoutUnit(10)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-
-  iterator.SetParent(column2);
-  // #child1 fragment in second column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit()), fragment->Size());
-  grandchild_iterator.SetParent(fragment);
-  // #grandchild1 fragment in second column
-  fragment = grandchild_iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(50), LayoutUnit(20)), fragment->Size());
-  // #grandchild2 fragment in second column
-  fragment = grandchild_iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit(20)), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(40), LayoutUnit(20)), fragment->Size());
-  EXPECT_FALSE(grandchild_iterator.NextChild());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x70
+        offset:0,0 size:75x60
+          offset:0,0 size:50x100
+        offset:0,60 size:85x10
+      offset:110,0 size:100x0
+        offset:0,0 size:75x0
+          offset:0,0 size:50x20
+          offset:0,20 size:40x20
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, FloatInOneColumn) {
@@ -568,35 +372,14 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-  // #child fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(75), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:75x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInOneColumn) {
@@ -618,41 +401,15 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-  // #child1 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(15), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  // #child2 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(84), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(16), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:15x100
+        offset:84,0 size:16x100
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 TEST_F(NGColumnLayoutAlgorithmTest, TwoFloatsInTwoColumns) {
@@ -674,60 +431,18 @@
     </div>
   )HTML");
 
-  NGBlockNode container(ToLayoutBox(GetLayoutObjectByElementId("container")));
-  RefPtr<NGConstraintSpace> space = ConstructBlockLayoutTestConstraintSpace(
-      kHorizontalTopBottom, TextDirection::kLtr,
-      NGLogicalSize(LayoutUnit(1000), NGSizeIndefinite));
-  RefPtr<const NGPhysicalBoxFragment> parent_fragment =
-      RunBlockLayoutAlgorithm(*space, container);
-
-  FragmentChildIterator iterator(parent_fragment.Get());
-  const auto* fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(320), LayoutUnit(100)), fragment->Size());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-
-  // first column fragment
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-
-  // second column fragment
-  const auto* column2 = iterator.NextChild();
-  ASSERT_TRUE(column2);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(110), LayoutUnit()), column2->Offset());
-  EXPECT_FALSE(iterator.NextChild());
-
-  iterator.SetParent(fragment);
-  // #child1 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(15), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  // #child2 fragment in first column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(84), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(16), LayoutUnit(100)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-
-  iterator.SetParent(column2);
-  // #child1 fragment in second column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(15), LayoutUnit(50)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  // #child2 fragment in second column
-  fragment = iterator.NextChild();
-  ASSERT_TRUE(fragment);
-  EXPECT_EQ(NGPhysicalOffset(LayoutUnit(84), LayoutUnit()), fragment->Offset());
-  EXPECT_EQ(NGPhysicalSize(LayoutUnit(16), LayoutUnit(50)), fragment->Size());
-  EXPECT_EQ(0UL, fragment->Children().size());
-  EXPECT_FALSE(iterator.NextChild());
+  String dump = DumpFragmentTree(GetElementById("container"));
+  String expectation = R"DUMP(.:: LayoutNG Physical Fragment Tree ::.
+  offset:unplaced size:1000x100
+    offset:0,0 size:320x100
+      offset:0,0 size:100x100
+        offset:0,0 size:15x100
+        offset:84,0 size:16x100
+      offset:110,0 size:100x50
+        offset:0,0 size:15x50
+        offset:84,0 size:16x50
+)DUMP";
+  EXPECT_EQ(expectation, dump);
 }
 
 }  // anonymous namespace
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
index b121c66..a439b4f 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.cc
@@ -15,14 +15,15 @@
     Vector<NGBaseline>& baselines,
     unsigned border_edges,  // NGBorderEdges::Physical
     RefPtr<NGBreakToken> break_token)
-    : NGPhysicalFragment(layout_object,
-                         style,
-                         size,
-                         kFragmentBox,
-                         std::move(break_token)),
-      overflow_(overflow) {
-  children_.swap(children);
-  baselines_.swap(baselines);
+    : NGPhysicalContainerFragment(layout_object,
+                                  style,
+                                  size,
+                                  kFragmentBox,
+                                  children,
+                                  std::move(break_token)),
+      overflow_(overflow),
+      baselines_(std::move(baselines)) {
+  DCHECK(baselines.IsEmpty());  // Ensure move semantics is used.
   border_edge_ = border_edges;
 }
 
@@ -36,15 +37,9 @@
 }
 
 void NGPhysicalBoxFragment::UpdateVisualRect() const {
-  LayoutRect visual_rect(LayoutPoint(),
-                         LayoutSize(Size().width, Size().height));
-  for (const auto& child : children_) {
-    LayoutRect child_visual_rect = child->VisualRect();
-    child_visual_rect.Move(child->Offset().left, child->Offset().top);
-    visual_rect.Unite(child_visual_rect);
-  }
+  NGPhysicalContainerFragment::UpdateVisualRect();
+
   // TODO(kojii): Add its own visual overflow (e.g., box-shadow)
-  SetVisualRect(visual_rect);
 }
 
 RefPtr<NGPhysicalFragment> NGPhysicalBoxFragment::CloneWithoutOffset() const {
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
index 8408183..f3bac30 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_box_fragment.h
@@ -7,11 +7,12 @@
 
 #include "core/CoreExport.h"
 #include "core/layout/ng/inline/ng_baseline.h"
-#include "core/layout/ng/ng_physical_fragment.h"
+#include "core/layout/ng/ng_physical_container_fragment.h"
 
 namespace blink {
 
-class CORE_EXPORT NGPhysicalBoxFragment final : public NGPhysicalFragment {
+class CORE_EXPORT NGPhysicalBoxFragment final
+    : public NGPhysicalContainerFragment {
  public:
   // This modifies the passed-in children vector.
   NGPhysicalBoxFragment(LayoutObject* layout_object,
@@ -26,10 +27,6 @@
   // Returns the total size, including the contents outside of the border-box.
   NGPhysicalSize OverflowSize() const { return overflow_; }
 
-  const Vector<RefPtr<NGPhysicalFragment>>& Children() const {
-    return children_;
-  }
-
   const NGBaseline* Baseline(const NGBaselineRequest&) const;
 
   void UpdateVisualRect() const override;
@@ -38,7 +35,6 @@
 
  private:
   NGPhysicalSize overflow_;
-  Vector<RefPtr<NGPhysicalFragment>> children_;
   Vector<NGBaseline> baselines_;
 };
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.cc
new file mode 100644
index 0000000..9ec9b70
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.cc
@@ -0,0 +1,36 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "core/layout/ng/ng_physical_container_fragment.h"
+
+namespace blink {
+
+NGPhysicalContainerFragment::NGPhysicalContainerFragment(
+    LayoutObject* layout_object,
+    const ComputedStyle& style,
+    NGPhysicalSize size,
+    NGFragmentType type,
+    Vector<RefPtr<NGPhysicalFragment>>& children,
+    RefPtr<NGBreakToken> break_token)
+    : NGPhysicalFragment(layout_object,
+                         style,
+                         size,
+                         type,
+                         std::move(break_token)),
+      children_(std::move(children)) {
+  DCHECK(children.IsEmpty());  // Ensure move semantics is used.
+}
+
+void NGPhysicalContainerFragment::UpdateVisualRect() const {
+  LayoutRect visual_rect(LayoutPoint(),
+                         LayoutSize(Size().width, Size().height));
+  for (const auto& child : children_) {
+    LayoutRect child_visual_rect = child->VisualRect();
+    child_visual_rect.Move(child->Offset().left, child->Offset().top);
+    visual_rect.Unite(child_visual_rect);
+  }
+  SetVisualRect(visual_rect);
+}
+
+}  // namespace blink
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.h
new file mode 100644
index 0000000..65818e8
--- /dev/null
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_container_fragment.h
@@ -0,0 +1,42 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NGPhysicalContainerFragment_h
+#define NGPhysicalContainerFragment_h
+
+#include "core/CoreExport.h"
+#include "core/layout/ng/inline/ng_baseline.h"
+#include "core/layout/ng/ng_physical_fragment.h"
+
+namespace blink {
+
+class CORE_EXPORT NGPhysicalContainerFragment : public NGPhysicalFragment {
+ public:
+  const Vector<RefPtr<NGPhysicalFragment>>& Children() const {
+    return children_;
+  }
+
+  void UpdateVisualRect() const override;
+
+ protected:
+  // This modifies the passed-in children vector.
+  NGPhysicalContainerFragment(LayoutObject*,
+                              const ComputedStyle&,
+                              NGPhysicalSize,
+                              NGFragmentType,
+                              Vector<RefPtr<NGPhysicalFragment>>& children,
+                              RefPtr<NGBreakToken> = nullptr);
+
+  Vector<RefPtr<NGPhysicalFragment>> children_;
+};
+
+DEFINE_TYPE_CASTS(NGPhysicalContainerFragment,
+                  NGPhysicalFragment,
+                  fragment,
+                  fragment->IsContainer(),
+                  fragment.IsContainer());
+
+}  // namespace blink
+
+#endif  // NGPhysicalContainerFragment_h
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
index ad8e0cba..33fe111 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.cc
@@ -16,70 +16,114 @@
 namespace blink {
 namespace {
 
-#ifndef NDEBUG
-void AppendFragmentOffsetAndSize(const NGPhysicalFragment* fragment,
-                                 StringBuilder* string_builder) {
-  string_builder->Append("offset:");
-  if (fragment->IsPlaced())
-    string_builder->Append(fragment->Offset().ToString());
-  else
-    string_builder->Append("unplaced");
-  string_builder->Append(" size:");
-  string_builder->Append(fragment->Size().ToString());
+bool AppendFragmentOffsetAndSize(const NGPhysicalFragment* fragment,
+                                 StringBuilder* builder,
+                                 NGPhysicalFragment::DumpFlags flags,
+                                 bool has_content) {
+  if (flags & NGPhysicalFragment::DumpOffset) {
+    if (has_content)
+      builder->Append(" ");
+    builder->Append("offset:");
+    if (fragment->IsPlaced())
+      builder->Append(fragment->Offset().ToString());
+    else
+      builder->Append("unplaced");
+    has_content = true;
+  }
+  if (flags & NGPhysicalFragment::DumpSize) {
+    if (has_content)
+      builder->Append(" ");
+    builder->Append("size:");
+    builder->Append(fragment->Size().ToString());
+    has_content = true;
+  }
+  return has_content;
 }
 
 void AppendFragmentToString(const NGPhysicalFragment* fragment,
-                            StringBuilder* string_builder,
+                            StringBuilder* builder,
+                            NGPhysicalFragment::DumpFlags flags,
                             unsigned indent = 2) {
-  for (unsigned i = 0; i < indent; i++)
-    string_builder->Append(" ");
+  if (flags & NGPhysicalFragment::DumpIndentation) {
+    for (unsigned i = 0; i < indent; i++)
+      builder->Append(" ");
+  }
 
+  bool has_content = false;
   if (fragment->IsBox()) {
-    string_builder->Append("PhysicalBoxFragment ");
-    AppendFragmentOffsetAndSize(fragment, string_builder);
+    if (flags & NGPhysicalFragment::DumpType) {
+      builder->Append("Box");
+      has_content = true;
+    }
+    has_content =
+        AppendFragmentOffsetAndSize(fragment, builder, flags, has_content);
 
     const auto* box = ToNGPhysicalBoxFragment(fragment);
-    string_builder->Append(" overflow:");
-    string_builder->Append(box->OverflowSize().ToString());
-    string_builder->Append("\n");
+    if (flags & NGPhysicalFragment::DumpOverflow) {
+      if (has_content)
+        builder->Append(" ");
+      builder->Append("overflow:");
+      builder->Append(box->OverflowSize().ToString());
+      has_content = true;
+    }
+    builder->Append("\n");
 
-    const auto& children = box->Children();
-    for (unsigned i = 0; i < children.size(); i++)
-      AppendFragmentToString(children[i].Get(), string_builder, indent + 2);
+    if (flags & NGPhysicalFragment::DumpSubtree) {
+      const auto& children = box->Children();
+      for (unsigned i = 0; i < children.size(); i++)
+        AppendFragmentToString(children[i].Get(), builder, flags, indent + 2);
+    }
     return;
   }
 
   if (fragment->IsLineBox()) {
-    string_builder->Append("NGPhysicalLineBoxFragment ");
-    AppendFragmentOffsetAndSize(fragment, string_builder);
+    if (flags & NGPhysicalFragment::DumpType) {
+      builder->Append("LineBox");
+      has_content = true;
+    }
+    has_content =
+        AppendFragmentOffsetAndSize(fragment, builder, flags, has_content);
+    builder->Append("\n");
 
-    const auto* line_box = ToNGPhysicalLineBoxFragment(fragment);
-    string_builder->Append("\n");
-
-    const auto& children = line_box->Children();
-    for (unsigned i = 0; i < children.size(); i++)
-      AppendFragmentToString(children[i].Get(), string_builder, indent + 2);
-    return;
+    if (flags & NGPhysicalFragment::DumpSubtree) {
+      const auto* line_box = ToNGPhysicalLineBoxFragment(fragment);
+      const auto& children = line_box->Children();
+      for (unsigned i = 0; i < children.size(); i++)
+        AppendFragmentToString(children[i].Get(), builder, flags, indent + 2);
+      return;
+    }
   }
 
   if (fragment->IsText()) {
-    string_builder->Append("PhysicalTextFragment ");
-    AppendFragmentOffsetAndSize(fragment, string_builder);
+    if (flags & NGPhysicalFragment::DumpType) {
+      builder->Append("Text");
+      has_content = true;
+    }
+    has_content =
+        AppendFragmentOffsetAndSize(fragment, builder, flags, has_content);
 
-    const auto* text = ToNGPhysicalTextFragment(fragment);
-    string_builder->Append(" start: ");
-    string_builder->Append(String::Format("%u", text->StartOffset()));
-    string_builder->Append(" end: ");
-    string_builder->Append(String::Format("%u", text->EndOffset()));
-    string_builder->Append("\n");
+    if (flags & NGPhysicalFragment::DumpTextOffsets) {
+      const auto* text = ToNGPhysicalTextFragment(fragment);
+      if (has_content)
+        builder->Append(" ");
+      builder->Append("start: ");
+      builder->Append(String::Format("%u", text->StartOffset()));
+      builder->Append(" end: ");
+      builder->Append(String::Format("%u", text->EndOffset()));
+      has_content = true;
+    }
+    builder->Append("\n");
     return;
   }
 
-  string_builder->Append("Unknown fragment type ");
-  AppendFragmentOffsetAndSize(fragment, string_builder);
-  string_builder->Append("\n");
+  if (flags & NGPhysicalFragment::DumpType) {
+    builder->Append("Unknown fragment type");
+    has_content = true;
+  }
+  has_content =
+      AppendFragmentOffsetAndSize(fragment, builder, flags, has_content);
+  builder->Append("\n");
 }
-#endif  // !NDEBUG
 
 }  // namespace
 
@@ -166,12 +210,17 @@
                         Offset().ToString().Ascii().data(), IsPlaced());
 }
 
+String NGPhysicalFragment::DumpFragmentTree(DumpFlags flags) const {
+  StringBuilder string_builder;
+  if (flags & DumpHeaderText)
+    string_builder.Append(".:: LayoutNG Physical Fragment Tree ::.\n");
+  AppendFragmentToString(this, &string_builder, flags);
+  return string_builder.ToString();
+}
+
 #ifndef NDEBUG
 void NGPhysicalFragment::ShowFragmentTree() const {
-  StringBuilder string_builder;
-  string_builder.Append(".:: LayoutNG Physical Fragment Tree ::.\n");
-  AppendFragmentToString(this, &string_builder);
-  fprintf(stderr, "%s\n", string_builder.ToString().Utf8().data());
+  fprintf(stderr, "%s\n", DumpFragmentTree(DumpAll).Utf8().data());
 }
 #endif  // !NDEBUG
 
diff --git a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
index f8f5c18..c2edfc5 100644
--- a/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
+++ b/third_party/WebKit/Source/core/layout/ng/ng_physical_fragment.h
@@ -54,6 +54,10 @@
   ~NGPhysicalFragment();
 
   NGFragmentType Type() const { return static_cast<NGFragmentType>(type_); }
+  bool IsContainer() const {
+    return Type() == NGFragmentType::kFragmentBox ||
+           Type() == NGFragmentType::kFragmentLineBox;
+  }
   bool IsBox() const { return Type() == NGFragmentType::kFragmentBox; }
   bool IsText() const { return Type() == NGFragmentType::kFragmentText; }
   bool IsLineBox() const { return Type() == NGFragmentType::kFragmentLineBox; }
@@ -109,6 +113,21 @@
 
   String ToString() const;
 
+  enum DumpFlag {
+    DumpHeaderText = 0x1,
+    DumpSubtree = 0x2,
+    DumpIndentation = 0x4,
+    DumpType = 0x8,
+    DumpOffset = 0x10,
+    DumpSize = 0x20,
+    DumpOverflow = 0x40,
+    DumpTextOffsets = 0x80,
+    DumpAll = -1
+  };
+  typedef int DumpFlags;
+
+  String DumpFragmentTree(DumpFlags) const;
+
 #ifndef NDEBUG
   void ShowFragmentTree() const;
 #endif
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp
index 1c1b73a..e0210e3 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.cpp
@@ -97,16 +97,20 @@
 }
 
 void LayoutSVGModelObject::ComputeLayerHitTestRects(
-    LayerHitTestRects& rects) const {
+    LayerHitTestRects& rects,
+    TouchAction supported_fast_actions) const {
   // Using just the rect for the SVGRoot is good enough for now.
-  SVGLayoutSupport::FindTreeRootObject(this)->ComputeLayerHitTestRects(rects);
+  SVGLayoutSupport::FindTreeRootObject(this)->ComputeLayerHitTestRects(
+      rects, supported_fast_actions);
 }
 
 void LayoutSVGModelObject::AddLayerHitTestRects(
     LayerHitTestRects&,
     const PaintLayer* current_layer,
     const LayoutPoint& layer_offset,
-    const LayoutRect& container_rect) const {
+    TouchAction supported_fast_actions,
+    const LayoutRect& container_rect,
+    TouchAction container_whitelisted_touch_action) const {
   // We don't walk into SVG trees at all - just report their container.
 }
 
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h
index e2399cd..c8df58c 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGModelObject.h
@@ -71,7 +71,7 @@
       LayoutGeometryMap&) const final;
   void StyleDidChange(StyleDifference, const ComputedStyle* old_style) override;
 
-  void ComputeLayerHitTestRects(LayerHitTestRects&) const final;
+  void ComputeLayerHitTestRects(LayerHitTestRects&, TouchAction) const final;
 
   SVGElement* GetElement() const {
     return ToSVGElement(LayoutObject::GetNode());
@@ -82,10 +82,13 @@
   }
 
  protected:
-  void AddLayerHitTestRects(LayerHitTestRects&,
-                            const PaintLayer* current_composited_layer,
-                            const LayoutPoint& layer_offset,
-                            const LayoutRect& container_rect) const final;
+  void AddLayerHitTestRects(
+      LayerHitTestRects&,
+      const PaintLayer* current_composited_layer,
+      const LayoutPoint& layer_offset,
+      TouchAction supported_fast_actions,
+      const LayoutRect& container_rect,
+      TouchAction container_whitelisted_touch_action) const final;
   void WillBeDestroyed() override;
 
  private:
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
index f9454e7..2315045b3 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.cpp
@@ -45,7 +45,7 @@
       cue_load_timer_(TaskRunnerHelper::Get(TaskType::kNetworking, &document),
                       this,
                       &TextTrackLoader::CueLoadTimerFired),
-      state_(kIdle),
+      state_(kLoading),
       new_cues_available_(false) {}
 
 TextTrackLoader::~TextTrackLoader() {}
diff --git a/third_party/WebKit/Source/core/loader/TextTrackLoader.h b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
index 2d1bc89..e25d480f 100644
--- a/third_party/WebKit/Source/core/loader/TextTrackLoader.h
+++ b/third_party/WebKit/Source/core/loader/TextTrackLoader.h
@@ -60,7 +60,7 @@
   bool Load(const KURL&, CrossOriginAttributeValue);
   void CancelLoad();
 
-  enum State { kIdle, kLoading, kFinished, kFailed };
+  enum State { kLoading, kFinished, kFailed };
   State LoadState() { return state_; }
 
   void GetNewCues(HeapVector<Member<TextTrackCue>>& output_cues);
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
index 1b23824..930d1e3b4 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinator.cpp
@@ -555,7 +555,7 @@
 }
 
 using GraphicsLayerHitTestRects =
-    WTF::HashMap<const GraphicsLayer*, Vector<LayoutRect>>;
+    WTF::HashMap<const GraphicsLayer*, Vector<TouchActionRect>>;
 
 // In order to do a DFS cross-frame walk of the Layer tree, we need to know
 // which Layers have child frames inside of them. This computes a mapping for
@@ -607,29 +607,33 @@
 
     GraphicsLayerHitTestRects::iterator gl_iter =
         graphics_rects.find(graphics_layer);
-    Vector<LayoutRect>* gl_rects;
-    if (gl_iter == graphics_rects.end())
-      gl_rects = &graphics_rects.insert(graphics_layer, Vector<LayoutRect>())
-                      .stored_value->value;
-    else
+    Vector<TouchActionRect>* gl_rects;
+    if (gl_iter == graphics_rects.end()) {
+      gl_rects =
+          &graphics_rects.insert(graphics_layer, Vector<TouchActionRect>())
+               .stored_value->value;
+    } else {
       gl_rects = &gl_iter->value;
+    }
 
     // Transform each rect to the co-ordinate space of the graphicsLayer.
     for (size_t i = 0; i < layer_iter->value.size(); ++i) {
-      LayoutRect rect = layer_iter->value[i];
+      TouchActionRect rect = layer_iter->value[i];
       if (composited_layer != cur_layer) {
         FloatQuad compositor_quad = geometry_map.MapToAncestor(
-            FloatRect(rect), &composited_layer->GetLayoutObject());
-        rect = LayoutRect(compositor_quad.BoundingBox());
+            FloatRect(rect.rect), &composited_layer->GetLayoutObject());
+        rect.rect = LayoutRect(compositor_quad.BoundingBox());
         // If the enclosing composited layer itself is scrolled, we have to undo
         // the subtraction of its scroll offset since we want the offset
         // relative to the scrolling content, not the element itself.
-        if (composited_layer->GetLayoutObject().HasOverflowClip())
-          rect.Move(composited_layer->GetLayoutBox()->ScrolledContentOffset());
+        if (composited_layer->GetLayoutObject().HasOverflowClip()) {
+          rect.rect.Move(
+              composited_layer->GetLayoutBox()->ScrolledContentOffset());
+        }
       }
       PaintLayer::MapRectInPaintInvalidationContainerToBacking(
-          composited_layer->GetLayoutObject(), rect);
-      rect.Move(-graphics_layer->OffsetFromLayoutObject());
+          composited_layer->GetLayoutObject(), rect.rect);
+      rect.rect.Move(-graphics_layer->OffsetFromLayoutObject());
 
       gl_rects->push_back(rect);
     }
@@ -775,7 +779,6 @@
   // on GraphicsLayer instead of Layer, but we have no good hook into the
   // lifetime of a GraphicsLayer.
   GraphicsLayerHitTestRects graphics_layer_rects;
-  WTF::HashMap<const GraphicsLayer*, TouchAction> paint_layer_touch_action;
   for (const PaintLayer* layer : layers_with_touch_rects_) {
     if (layer->GetLayoutObject().GetFrameView() &&
         layer->GetLayoutObject().GetFrameView()->ShouldThrottleRendering()) {
@@ -783,13 +786,15 @@
     }
     GraphicsLayer* main_graphics_layer =
         layer->GraphicsLayerBacking(&layer->GetLayoutObject());
-    if (main_graphics_layer)
-      graphics_layer_rects.insert(main_graphics_layer, Vector<LayoutRect>());
+    if (main_graphics_layer) {
+      graphics_layer_rects.insert(main_graphics_layer,
+                                  Vector<TouchActionRect>());
+    }
     GraphicsLayer* scrolling_contents_layer = layer->GraphicsLayerBacking();
     if (scrolling_contents_layer &&
         scrolling_contents_layer != main_graphics_layer) {
       graphics_layer_rects.insert(scrolling_contents_layer,
-                                  Vector<LayoutRect>());
+                                  Vector<TouchActionRect>());
     }
   }
 
@@ -803,16 +808,6 @@
       if (!composited_layer)
         continue;
       layers_with_touch_rects_.insert(composited_layer);
-      GraphicsLayer* main_graphics_layer =
-          composited_layer->GraphicsLayerBacking(
-              &composited_layer->GetLayoutObject());
-      if (main_graphics_layer) {
-        TouchAction effective_touch_action =
-            TouchActionUtil::ComputeEffectiveTouchAction(
-                *(composited_layer->EnclosingNode()));
-        paint_layer_touch_action.insert(main_graphics_layer,
-                                        effective_touch_action);
-      }
     }
   }
 
@@ -821,15 +816,10 @@
 
   for (const auto& layer_rect : graphics_layer_rects) {
     const GraphicsLayer* graphics_layer = layer_rect.key;
-    TouchAction effective_touch_action = TouchAction::kTouchActionNone;
-    const auto& layer_touch_action =
-        paint_layer_touch_action.find(graphics_layer);
-    if (layer_touch_action != paint_layer_touch_action.end())
-      effective_touch_action = layer_touch_action->value;
     WebVector<WebTouchInfo> touch(layer_rect.value.size());
     for (size_t i = 0; i < layer_rect.value.size(); ++i) {
-      touch[i].rect = EnclosingIntRect(layer_rect.value[i]);
-      touch[i].touch_action = effective_touch_action;
+      touch[i].rect = EnclosingIntRect(layer_rect.value[i].rect);
+      touch[i].touch_action = layer_rect.value[i].whitelisted_touch_action;
     }
     graphics_layer->PlatformLayer()->SetTouchEventHandlerRegion(touch);
   }
@@ -1070,7 +1060,8 @@
 static void AccumulateDocumentTouchEventTargetRects(
     LayerHitTestRects& rects,
     EventHandlerRegistry::EventHandlerClass event_class,
-    const Document* document) {
+    const Document* document,
+    TouchAction supported_fast_actions) {
   DCHECK(document);
   const EventTargetSet* targets =
       document->GetPage()->GetEventHandlerRegistry().EventHandlerTargets(
@@ -1103,7 +1094,7 @@
       if (window || node == document || node == document->documentElement() ||
           node == document->body()) {
         if (LayoutViewItem layout_view = document->GetLayoutViewItem()) {
-          layout_view.ComputeLayerHitTestRects(rects);
+          layout_view.ComputeLayerHitTestRects(rects, supported_fast_actions);
         }
         return;
       }
@@ -1127,8 +1118,8 @@
       continue;
 
     if (node->IsDocumentNode() && node != document) {
-      AccumulateDocumentTouchEventTargetRects(rects, event_class,
-                                              ToDocument(node));
+      AccumulateDocumentTouchEventTargetRects(
+          rects, event_class, ToDocument(node), supported_fast_actions);
     } else if (LayoutObject* layout_object = node->GetLayoutObject()) {
       // If the set also contains one of our ancestor nodes then processing
       // this node would be redundant.
@@ -1155,10 +1146,12 @@
         // recomputed. Non-composited scrolling occurs on the main thread, so
         // we're not getting much benefit from compositor touch hit testing in
         // this case anyway.
-        if (enclosing_non_composited_scroll_layer)
-          enclosing_non_composited_scroll_layer->ComputeSelfHitTestRects(rects);
+        if (enclosing_non_composited_scroll_layer) {
+          enclosing_non_composited_scroll_layer->ComputeSelfHitTestRects(
+              rects, supported_fast_actions);
+        }
 
-        layout_object->ComputeLayerHitTestRects(rects);
+        layout_object->ComputeLayerHitTestRects(rects, supported_fast_actions);
       }
     }
   }
@@ -1173,10 +1166,14 @@
     return;
 
   AccumulateDocumentTouchEventTargetRects(
-      rects, EventHandlerRegistry::kTouchStartOrMoveEventBlocking, document);
+      rects, EventHandlerRegistry::kTouchAction, document,
+      TouchAction::kTouchActionAuto);
+  AccumulateDocumentTouchEventTargetRects(
+      rects, EventHandlerRegistry::kTouchStartOrMoveEventBlocking, document,
+      TouchAction::kTouchActionNone);
   AccumulateDocumentTouchEventTargetRects(
       rects, EventHandlerRegistry::kTouchStartOrMoveEventBlockingLowLatency,
-      document);
+      document, TouchAction::kTouchActionNone);
 }
 
 void ScrollingCoordinator::
diff --git a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
index 8fbc827..e07e1f6b 100644
--- a/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
+++ b/third_party/WebKit/Source/core/page/scrolling/ScrollingCoordinatorTest.cpp
@@ -50,6 +50,7 @@
 #include "public/platform/WebLayer.h"
 #include "public/platform/WebLayerPositionConstraint.h"
 #include "public/platform/WebLayerTreeView.h"
+#include "public/platform/WebRect.h"
 #include "public/platform/WebURLLoaderMockFactory.h"
 #include "public/web/WebSettings.h"
 #include "public/web/WebViewClient.h"
@@ -544,14 +545,7 @@
 
   Element* scrollable_element =
       GetFrame()->GetDocument()->getElementById("scrollable");
-  DCHECK(scrollable_element);
-  ForceFullCompositingUpdate();
-
-  LayoutObject* layout_object = scrollable_element->GetLayoutObject();
-  ASSERT_TRUE(layout_object->IsBox());
-  ASSERT_TRUE(layout_object->HasLayer());
-
-  LayoutBox* box = ToLayoutBox(layout_object);
+  LayoutBox* box = ToLayoutBox(scrollable_element->GetLayoutObject());
   ASSERT_TRUE(box->UsesCompositedScrolling());
   ASSERT_EQ(kPaintsIntoOwnBacking, box->Layer()->GetCompositingState());
 
@@ -563,7 +557,71 @@
   WebVector<WebRect> rects =
       web_layer->TouchEventHandlerRegionForTouchActionForTesting(
           TouchAction::kTouchActionPanX | TouchAction::kTouchActionPanDown);
-  DCHECK_EQ(rects.size(), 1u);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 0, 1000, 1000));
+}
+
+TEST_P(ScrollingCoordinatorTest, touchActionRegions) {
+  RegisterMockedHttpURLLoad("touch-action-regions.html");
+  NavigateTo(base_url_ + "touch-action-regions.html");
+  ForceFullCompositingUpdate();
+
+  Element* scrollable_element =
+      GetFrame()->GetDocument()->getElementById("scrollable");
+  LayoutBox* box = ToLayoutBox(scrollable_element->GetLayoutObject());
+  ASSERT_TRUE(box->UsesCompositedScrolling());
+  ASSERT_EQ(kPaintsIntoOwnBacking, box->Layer()->GetCompositingState());
+
+  CompositedLayerMapping* composited_layer_mapping =
+      box->Layer()->GetCompositedLayerMapping();
+
+  GraphicsLayer* graphics_layer = composited_layer_mapping->MainGraphicsLayer();
+  WebLayer* web_layer = graphics_layer->PlatformLayer();
+
+  WebVector<WebRect> rects =
+      web_layer->TouchEventHandlerRegionForTouchActionForTesting(
+          TouchAction::kTouchActionPanDown | TouchAction::kTouchActionPanX);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 0, 100, 100));
+
+  rects = web_layer->TouchEventHandlerRegionForTouchActionForTesting(
+      TouchAction::kTouchActionPanDown | TouchAction::kTouchActionPanRight);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 0, 50, 50));
+
+  rects = web_layer->TouchEventHandlerRegionForTouchActionForTesting(
+      TouchAction::kTouchActionPanDown);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 100, 100, 100));
+}
+
+TEST_P(ScrollingCoordinatorTest, touchActionBlockingHandler) {
+  RegisterMockedHttpURLLoad("touch-action-blocking-handler.html");
+  NavigateTo(base_url_ + "touch-action-blocking-handler.html");
+  ForceFullCompositingUpdate();
+
+  Element* scrollable_element =
+      GetFrame()->GetDocument()->getElementById("scrollable");
+  LayoutBox* box = ToLayoutBox(scrollable_element->GetLayoutObject());
+  ASSERT_TRUE(box->UsesCompositedScrolling());
+  ASSERT_EQ(kPaintsIntoOwnBacking, box->Layer()->GetCompositingState());
+
+  CompositedLayerMapping* composited_layer_mapping =
+      box->Layer()->GetCompositedLayerMapping();
+
+  GraphicsLayer* graphics_layer = composited_layer_mapping->MainGraphicsLayer();
+  WebLayer* web_layer = graphics_layer->PlatformLayer();
+
+  WebVector<WebRect> rects =
+      web_layer->TouchEventHandlerRegionForTouchActionForTesting(
+          TouchAction::kTouchActionNone);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 0, 100, 100));
+
+  rects = web_layer->TouchEventHandlerRegionForTouchActionForTesting(
+      TouchAction::kTouchActionPanY);
+  EXPECT_EQ(rects.size(), 1u);
+  EXPECT_EQ(IntRect(rects[0]), IntRect(0, 0, 1000, 1000));
 }
 
 TEST_P(ScrollingCoordinatorTest, overflowScrolling) {
diff --git a/third_party/WebKit/Source/core/paint/LayerHitTestRects.h b/third_party/WebKit/Source/core/paint/LayerHitTestRects.h
index cd48569..273d3a6 100644
--- a/third_party/WebKit/Source/core/paint/LayerHitTestRects.h
+++ b/third_party/WebKit/Source/core/paint/LayerHitTestRects.h
@@ -6,6 +6,7 @@
 #define LayerHitTestRects_h
 
 #include "platform/geometry/LayoutRect.h"
+#include "platform/graphics/TouchAction.h"
 #include "platform/wtf/HashMap.h"
 #include "platform/wtf/Vector.h"
 
@@ -13,7 +14,16 @@
 
 class PaintLayer;
 
-typedef WTF::HashMap<const PaintLayer*, Vector<LayoutRect>> LayerHitTestRects;
+struct TouchActionRect {
+  LayoutRect rect;
+  TouchAction whitelisted_touch_action;
+
+  TouchActionRect(LayoutRect layout_rect, TouchAction action)
+      : rect(layout_rect), whitelisted_touch_action(action) {}
+};
+
+typedef WTF::HashMap<const PaintLayer*, Vector<TouchActionRect>>
+    LayerHitTestRects;
 
 }  // namespace blink
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.cpp b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
index 07f341f..bf0498c 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.cpp
@@ -3239,15 +3239,22 @@
   return false;
 }
 
-void PaintLayer::AddLayerHitTestRects(LayerHitTestRects& rects) const {
-  ComputeSelfHitTestRects(rects);
+void PaintLayer::AddLayerHitTestRects(
+    LayerHitTestRects& rects,
+    TouchAction supported_fast_actions) const {
+  ComputeSelfHitTestRects(rects, supported_fast_actions);
   for (PaintLayer* child = FirstChild(); child; child = child->NextSibling())
-    child->AddLayerHitTestRects(rects);
+    child->AddLayerHitTestRects(rects, supported_fast_actions);
 }
 
-void PaintLayer::ComputeSelfHitTestRects(LayerHitTestRects& rects) const {
+void PaintLayer::ComputeSelfHitTestRects(
+    LayerHitTestRects& rects,
+    TouchAction supported_fast_actions) const {
   if (!size().IsEmpty()) {
-    Vector<LayoutRect> rect;
+    Vector<TouchActionRect> rect;
+    TouchAction whitelisted_touch_action =
+        GetLayoutObject().Style()->GetEffectiveTouchAction() &
+        supported_fast_actions;
 
     if (GetLayoutBox() && GetLayoutBox()->ScrollsOverflow()) {
       // For scrolling layers, rects are taken to be in the space of the
@@ -3256,21 +3263,26 @@
       // composited then the entire contents as well as they may be on another
       // composited layer. Skip reporting contents for non-composited layers as
       // they'll get projected to the same layer as the bounding box.
-      if (GetCompositingState() != kNotComposited && scrollable_area_)
-        rect.push_back(scrollable_area_->OverflowRect());
+      if (GetCompositingState() != kNotComposited && scrollable_area_) {
+        rect.push_back(TouchActionRect(scrollable_area_->OverflowRect(),
+                                       whitelisted_touch_action));
+      }
 
       rects.Set(this, rect);
       if (const PaintLayer* parent_layer = Parent()) {
         LayerHitTestRects::iterator iter = rects.find(parent_layer);
         if (iter == rects.end()) {
-          rects.insert(parent_layer, Vector<LayoutRect>())
-              .stored_value->value.push_back(PhysicalBoundingBox(parent_layer));
+          rects.insert(parent_layer, Vector<TouchActionRect>())
+              .stored_value->value.push_back(TouchActionRect(
+                  PhysicalBoundingBox(parent_layer), whitelisted_touch_action));
         } else {
-          iter->value.push_back(PhysicalBoundingBox(parent_layer));
+          iter->value.push_back(TouchActionRect(
+              PhysicalBoundingBox(parent_layer), whitelisted_touch_action));
         }
       }
     } else {
-      rect.push_back(LogicalBoundingBox());
+      rect.push_back(
+          TouchActionRect(LogicalBoundingBox(), whitelisted_touch_action));
       rects.Set(this, rect);
     }
   }
diff --git a/third_party/WebKit/Source/core/paint/PaintLayer.h b/third_party/WebKit/Source/core/paint/PaintLayer.h
index a9ac7e12..fe728488 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayer.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayer.h
@@ -644,10 +644,10 @@
   bool FixedToViewport() const;
   bool ScrollsWithRespectTo(const PaintLayer*) const;
 
-  void AddLayerHitTestRects(LayerHitTestRects&) const;
+  void AddLayerHitTestRects(LayerHitTestRects&, TouchAction) const;
 
   // Compute rects only for this layer
-  void ComputeSelfHitTestRects(LayerHitTestRects&) const;
+  void ComputeSelfHitTestRects(LayerHitTestRects&, TouchAction) const;
 
   // FIXME: This should probably return a ScrollableArea but a lot of internal
   // methods are mistakenly exposed.
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
index a8156bb..69afa22 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerScrollableArea.h
@@ -225,6 +225,7 @@
   ~PaintLayerScrollableArea() override;
   void Dispose();
 
+  void ForceVerticalScrollbarForFirstLayout() { SetHasVerticalScrollbar(true); }
   bool HasHorizontalScrollbar() const { return HorizontalScrollbar(); }
   bool HasVerticalScrollbar() const { return VerticalScrollbar(); }
 
diff --git a/third_party/WebKit/Source/core/testing/Internals.cpp b/third_party/WebKit/Source/core/testing/Internals.cpp
index 43d433d..df5bf5b 100644
--- a/third_party/WebKit/Source/core/testing/Internals.cpp
+++ b/third_party/WebKit/Source/core/testing/Internals.cpp
@@ -1709,7 +1709,8 @@
 unsigned Internals::touchStartOrMoveEventHandlerCount(
     Document* document) const {
   DCHECK(document);
-  return EventHandlerCount(
+  return EventHandlerCount(*document, EventHandlerRegistry::kTouchAction) +
+         EventHandlerCount(
              *document, EventHandlerRegistry::kTouchStartOrMoveEventBlocking) +
          EventHandlerCount(
              *document,
diff --git a/third_party/WebKit/Source/core/testing/data/touch-action-blocking-handler.html b/third_party/WebKit/Source/core/testing/data/touch-action-blocking-handler.html
new file mode 100644
index 0000000..a7efd7d
--- /dev/null
+++ b/third_party/WebKit/Source/core/testing/data/touch-action-blocking-handler.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style type="text/css">
+    #scrollable {
+      margin-top: 50px;
+      margin-left: 50px;
+      width: 200px;
+      height: 200px;
+      overflow: scroll;
+      touch-action: pan-y;
+    }
+    .content {
+      width: 1000px;
+      height: 900px;
+    }
+    #handler {
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="scrollable">
+    <div id="handler"></div>
+    <div class="content"></div>
+  </div>
+  <script>
+    // A blocking touch handler should prevent scrolling in that region.
+    document.getElementById('handler').addEventListener('touchstart', function(e) {
+      e.preventDefault();
+    });
+  </script>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/core/testing/data/touch-action-regions.html b/third_party/WebKit/Source/core/testing/data/touch-action-regions.html
new file mode 100644
index 0000000..e724573f
--- /dev/null
+++ b/third_party/WebKit/Source/core/testing/data/touch-action-regions.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <style type="text/css">
+    #scrollable {
+      margin-top: 50px;
+      margin-left: 50px;
+      width: 200px;
+      height: 200px;
+      overflow: scroll;
+    }
+    .content {
+      width: 1000px;
+      height: 1000px;
+    }
+    .region {
+      width: 100px;
+      height: 100px;
+    }
+  </style>
+</head>
+
+<body>
+  <div id="scrollable">
+    <div style="touch-action: pan-down pan-x;" class="region">
+      <div>
+        <div style="touch-action: pan-y pan-right; width: 50px; height: 50px;"></div>
+      </div>
+    </div>
+    <div style="touch-action: pan-down;" class="region"></div>
+    <div class="content"></div>
+  </div>
+</body>
+</html>
diff --git a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
index c844b74..8ddf5ce 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXObjectCacheImpl.cpp
@@ -1319,6 +1319,18 @@
   if (!document_->GetExecutionContext())
     return;
 
+  // Passing an Origin to Mojo crashes if the host is empty because
+  // blink::SecurityOrigin sets unique to false, but url::Origin sets
+  // unique to true. This only happens for some obscure corner cases
+  // like on Android where the system registers unusual protocol handlers,
+  // and we don't need any special permissions in those cases.
+  //
+  // http://crbug.com/759528 and http://crbug.com/762716
+  if (document_->Url().Protocol() != "file" &&
+      document_->Url().Host().IsEmpty()) {
+    return;
+  }
+
   ConnectToPermissionService(document_->GetExecutionContext(),
                              mojo::MakeRequest(&permission_service_));
 
@@ -1347,6 +1359,9 @@
   if (accessibility_event_permission_ != mojom::PermissionStatus::ASK)
     return;
 
+  if (!permission_service_)
+    return;
+
   permission_service_->RequestPermission(
       CreatePermissionDescriptor(
           mojom::blink::PermissionName::ACCESSIBILITY_EVENTS),
diff --git a/third_party/WebKit/Source/modules/media_controls/BUILD.gn b/third_party/WebKit/Source/modules/media_controls/BUILD.gn
index 5cece65..e023686 100644
--- a/third_party/WebKit/Source/modules/media_controls/BUILD.gn
+++ b/third_party/WebKit/Source/modules/media_controls/BUILD.gn
@@ -54,8 +54,6 @@
     "elements/MediaControlPlayButtonElement.h",
     "elements/MediaControlRemainingTimeDisplayElement.cpp",
     "elements/MediaControlRemainingTimeDisplayElement.h",
-    "elements/MediaControlSliderElement.cpp",
-    "elements/MediaControlSliderElement.h",
     "elements/MediaControlTextTrackListElement.cpp",
     "elements/MediaControlTextTrackListElement.h",
     "elements/MediaControlTimeDisplayElement.cpp",
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
index 496d7a5..7520a96 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImpl.cpp
@@ -1204,13 +1204,6 @@
   // source or no longer have a source.
   download_button_->SetIsWanted(
       download_button_->ShouldDisplayDownloadButton());
-
-  if (MediaElement().getNetworkState() != HTMLMediaElement::kNetworkEmpty &&
-      MediaElement().getNetworkState() != HTMLMediaElement::kNetworkNoSource) {
-    setAttribute("class", "");
-  } else {
-    setAttribute("class", "not-loaded");
-  }
 }
 
 bool MediaControlsImpl::OverflowMenuVisible() {
diff --git a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
index 4f8a6f4..bfbef21a 100644
--- a/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/MediaControlsImplTest.cpp
@@ -713,6 +713,36 @@
   EXPECT_EQ(duration / 2, current_time_display->CurrentValue());
 }
 
+TEST_F(MediaControlsImplTest, VolumeSliderPaintInvalidationOnInput) {
+  EnsureSizing();
+
+  Element* volume_slider = VolumeSliderElement();
+
+  MockLayoutObject layout_object(volume_slider);
+  LayoutObject* prev_layout_object = volume_slider->GetLayoutObject();
+  volume_slider->SetLayoutObject(&layout_object);
+
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
+  Event* event = Event::Create(EventTypeNames::input);
+  volume_slider->DefaultEventHandler(event);
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
+
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
+  event = Event::Create(EventTypeNames::input);
+  volume_slider->DefaultEventHandler(event);
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
+
+  layout_object.ClearPaintInvalidationFlags();
+  EXPECT_FALSE(layout_object.ShouldDoFullPaintInvalidation());
+  event = Event::Create(EventTypeNames::input);
+  volume_slider->DefaultEventHandler(event);
+  EXPECT_TRUE(layout_object.ShouldDoFullPaintInvalidation());
+
+  volume_slider->SetLayoutObject(prev_layout_object);
+}
+
 TEST_F(MediaControlsImplTest, TimelineMetricsWidth) {
   MediaControls().MediaElement().SetSrc("https://example.com/foo.mp4");
   testing::RunPendingTasks();
@@ -829,7 +859,7 @@
   MouseUpAt(trackTwoThirds);
 
   EXPECT_LE(0.66 * duration, MediaControls().MediaElement().currentTime());
-  EXPECT_GE(0.70 * duration, MediaControls().MediaElement().currentTime());
+  EXPECT_GE(0.68 * duration, MediaControls().MediaElement().currentTime());
 
   GetHistogramTester().ExpectUniqueSample("Media.Timeline.SeekType." TIMELINE_W,
                                           2 /* SeekType::kDragFromElsewhere */,
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
index 36567a5..59ab136 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlCastButtonElement.cpp
@@ -68,7 +68,6 @@
     }
   }
   UpdateOverflowString();
-  SetClass("on", IsPlayingRemotely());
 }
 
 bool MediaControlCastButtonElement::WillRespondToMouseClickEvents() {
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
index 9d2f95e..8cc17ed 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlFullscreenButtonElement.cpp
@@ -26,7 +26,6 @@
 void MediaControlFullscreenButtonElement::SetIsFullscreen(bool is_fullscreen) {
   SetDisplayType(is_fullscreen ? kMediaExitFullscreenButton
                                : kMediaEnterFullscreenButton);
-  SetClass("fullscreen", is_fullscreen);
 }
 
 bool MediaControlFullscreenButtonElement::WillRespondToMouseClickEvents() {
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
index 18b052c..299006a 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.cpp
@@ -4,7 +4,6 @@
 
 #include "modules/media_controls/elements/MediaControlInputElement.h"
 
-#include "core/dom/DOMTokenList.h"
 #include "core/dom/events/Event.h"
 #include "core/html/HTMLLabelElement.h"
 #include "core/html/HTMLMediaElement.h"
@@ -175,14 +174,6 @@
   ctr_histogram.Count(static_cast<int>(event));
 }
 
-void MediaControlInputElement::SetClass(const AtomicString& class_name,
-                                        bool should_have_class) {
-  if (should_have_class)
-    classList().Add(class_name);
-  else
-    classList().Remove(class_name);
-}
-
 DEFINE_TRACE(MediaControlInputElement) {
   HTMLInputElement::Trace(visitor);
   MediaControlElementBase::Trace(visitor);
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
index 528035a3..9dca441 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlInputElement.h
@@ -59,9 +59,6 @@
   // Returns whether this element is used for the overflow menu.
   bool IsOverflowElement() const;
 
-  // Sets/removes a CSS class from this element based on |should_have_class|.
-  void SetClass(const AtomicString& class_name, bool should_have_class);
-
  private:
   friend class MediaControlInputElementTest;
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
index d9890ec8..c12eaeb 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlMuteButtonElement.cpp
@@ -28,9 +28,9 @@
   // TODO(mlamouri): checking for volume == 0 because the mute button will look
   // 'muted' when the volume is 0 even if the element is not muted. This allows
   // the painting and the display type to actually match.
-  bool muted = MediaElement().muted() || MediaElement().volume() == 0;
-  SetDisplayType(muted ? kMediaUnMuteButton : kMediaMuteButton);
-  SetClass("muted", muted);
+  SetDisplayType((MediaElement().muted() || MediaElement().volume() == 0)
+                     ? kMediaUnMuteButton
+                     : kMediaMuteButton);
   UpdateOverflowString();
 }
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
index fa96c1b..6bd48224 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlPlayButtonElement.cpp
@@ -28,7 +28,6 @@
 void MediaControlPlayButtonElement::UpdateDisplayType() {
   SetDisplayType(MediaElement().paused() ? kMediaPlayButton
                                          : kMediaPauseButton);
-  SetClass("pause", MediaElement().paused());
   UpdateOverflowString();
 }
 
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp
deleted file mode 100644
index 118ccdc..0000000
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "modules/media_controls/elements/MediaControlSliderElement.h"
-
-#include "core/InputTypeNames.h"
-#include "core/dom/ElementShadow.h"
-#include "core/html/HTMLDivElement.h"
-#include "platform/wtf/text/StringBuilder.h"
-
-namespace {
-
-void SetSegmentDivPosition(blink::HTMLDivElement* segment,
-                           int left,
-                           int width) {
-  StringBuilder builder;
-  builder.Append("width: ");
-  builder.AppendNumber(width);
-  builder.Append("%; left: ");
-  builder.AppendNumber(left);
-  builder.Append("%;");
-  segment->setAttribute("style", builder.ToAtomicString());
-}
-
-}  // namespace.
-
-namespace blink {
-
-MediaControlSliderElement::MediaControlSliderElement(
-    MediaControlsImpl& media_controls,
-    MediaControlElementType display_type)
-    : MediaControlInputElement(media_controls, display_type),
-      segment_highlight_before_(nullptr),
-      segment_highlight_after_(nullptr) {
-  EnsureUserAgentShadowRoot();
-  setType(InputTypeNames::range);
-  setAttribute(HTMLNames::stepAttr, "any");
-}
-
-void MediaControlSliderElement::SetupBarSegments() {
-  DCHECK((segment_highlight_after_ && segment_highlight_before_) ||
-         (!segment_highlight_after_ && !segment_highlight_before_));
-
-  if (segment_highlight_after_ || segment_highlight_before_)
-    return;
-
-  // The timeline element has a shadow root with the following
-  // structure:
-  //
-  // #shadow-root
-  //   - div
-  //     - div::-webkit-slider-runnable-track#track
-  ShadowRoot& shadow_root = Shadow()->OldestShadowRoot();
-  Element* track = shadow_root.getElementById(AtomicString("track"));
-  DCHECK(track);
-  track->setAttribute("class", "-internal-media-controls-segmented-track");
-
-  // Add the following structure to #track.
-  //
-  // div.-internal-track-segment-background (container)
-  //   - div.-internal-track-segment-highlight-before (blue highlight)
-  //   - div.-internal-track-segment-highlight-after (dark gray highlight)
-  HTMLDivElement* background = HTMLDivElement::Create(GetDocument());
-  background->setAttribute("class", "-internal-track-segment-background");
-  track->appendChild(background);
-
-  segment_highlight_before_ = HTMLDivElement::Create(GetDocument());
-  segment_highlight_before_->setAttribute(
-      "class", "-internal-track-segment-highlight-before");
-  background->appendChild(segment_highlight_before_);
-
-  segment_highlight_after_ = HTMLDivElement::Create(GetDocument());
-  segment_highlight_after_->setAttribute(
-      "class", "-internal-track-segment-highlight-after");
-  background->appendChild(segment_highlight_after_);
-}
-
-void MediaControlSliderElement::SetBeforeSegmentPosition(int left, int width) {
-  DCHECK(segment_highlight_before_);
-  SetSegmentDivPosition(segment_highlight_before_, left, width);
-}
-
-void MediaControlSliderElement::SetAfterSegmentPosition(int left, int width) {
-  DCHECK(segment_highlight_after_);
-  SetSegmentDivPosition(segment_highlight_after_, left, width);
-}
-
-DEFINE_TRACE(MediaControlSliderElement) {
-  visitor->Trace(segment_highlight_before_);
-  visitor->Trace(segment_highlight_after_);
-  MediaControlInputElement::Trace(visitor);
-}
-
-}  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.h
deleted file mode 100644
index d73f51d..0000000
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlSliderElement.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef MediaControlSliderElement_h
-#define MediaControlSliderElement_h
-
-#include "modules/ModulesExport.h"
-#include "modules/media_controls/elements/MediaControlInputElement.h"
-
-namespace blink {
-
-class MediaControlsImpl;
-
-// MediaControlInputElement with additional logic for sliders.
-class MODULES_EXPORT MediaControlSliderElement
-    : public MediaControlInputElement {
-  USING_GARBAGE_COLLECTED_MIXIN(MediaControlSliderElement);
-
- public:
-  DECLARE_VIRTUAL_TRACE();
-
- protected:
-  MediaControlSliderElement(MediaControlsImpl&, MediaControlElementType);
-
-  void SetupBarSegments();
-  void SetBeforeSegmentPosition(int left, int width);
-  void SetAfterSegmentPosition(int left, int width);
-
- private:
-  Member<HTMLDivElement> segment_highlight_before_;
-  Member<HTMLDivElement> segment_highlight_after_;
-};
-
-}  // namespace blink
-
-#endif  // MediaControlSliderElement_h
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.cpp
index 7a4b43b..dd3e7d7 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.cpp
@@ -5,6 +5,7 @@
 #include "modules/media_controls/elements/MediaControlTimelineElement.h"
 
 #include "core/HTMLNames.h"
+#include "core/InputTypeNames.h"
 #include "core/dom/events/Event.h"
 #include "core/events/KeyboardEvent.h"
 #include "core/events/PointerEvent.h"
@@ -18,17 +19,14 @@
 #include "public/platform/Platform.h"
 #include "public/platform/WebScreenInfo.h"
 
-namespace {
-
-const double kCurrentTimeBufferedDelta = 1.0;
-
-}  // namespace.
-
 namespace blink {
 
 MediaControlTimelineElement::MediaControlTimelineElement(
     MediaControlsImpl& media_controls)
-    : MediaControlSliderElement(media_controls, kMediaSlider) {
+    : MediaControlInputElement(media_controls, kMediaSlider) {
+  EnsureUserAgentShadowRoot();
+  setType(InputTypeNames::range);
+  setAttribute(HTMLNames::stepAttr, "any");
   SetShadowPseudoId(AtomicString("-webkit-media-controls-timeline"));
 }
 
@@ -38,15 +36,17 @@
 
 void MediaControlTimelineElement::SetPosition(double current_time) {
   setValue(String::Number(current_time));
-  current_time_ = current_time;
-  RenderBarSegments();
+
+  if (LayoutObject* layout_object = this->GetLayoutObject())
+    layout_object->SetShouldDoFullPaintInvalidation();
 }
 
 void MediaControlTimelineElement::SetDuration(double duration) {
   SetFloatingPointAttribute(HTMLNames::maxAttr,
                             std::isfinite(duration) ? duration : 0);
-  duration_ = duration;
-  RenderBarSegments();
+
+  if (LayoutObject* layout_object = this->GetLayoutObject())
+    layout_object->SetShouldDoFullPaintInvalidation();
 }
 
 void MediaControlTimelineElement::OnPlaying() {
@@ -136,56 +136,4 @@
   return 0;
 }
 
-void MediaControlTimelineElement::RenderBarSegments() {
-  SetupBarSegments();
-
-  // Draw the buffered range. Since the element may have multiple buffered
-  // ranges and it'd be distracting/'busy' to show all of them, show only the
-  // buffered range containing the current play head.
-  TimeRanges* buffered_time_ranges = MediaElement().buffered();
-  DCHECK(buffered_time_ranges);
-  if (std::isnan(duration_) || std::isinf(duration_) || !duration_ ||
-      std::isnan(current_time_)) {
-    SetBeforeSegmentPosition(0, 0);
-    SetAfterSegmentPosition(0, 0);
-    return;
-  }
-
-  int current_position = int((current_time_ / duration_) * 100);
-  for (unsigned i = 0; i < buffered_time_ranges->length(); ++i) {
-    float start = buffered_time_ranges->start(i, ASSERT_NO_EXCEPTION);
-    float end = buffered_time_ranges->end(i, ASSERT_NO_EXCEPTION);
-    // The delta is there to avoid corner cases when buffered
-    // ranges is out of sync with current time because of
-    // asynchronous media pipeline and current time caching in
-    // HTMLMediaElement.
-    // This is related to https://www.w3.org/Bugs/Public/show_bug.cgi?id=28125
-    // FIXME: Remove this workaround when WebMediaPlayer
-    // has an asynchronous pause interface.
-    if (std::isnan(start) || std::isnan(end) ||
-        start > current_time_ + kCurrentTimeBufferedDelta ||
-        end < current_time_) {
-      continue;
-    }
-
-    int start_position = int((start / duration_) * 100);
-    int end_position = int((end / duration_) * 100);
-
-    // Draw highlight before current time.
-    if (current_position > start_position)
-      SetBeforeSegmentPosition(start_position, current_position);
-
-    // Draw dark grey highlight after current time.
-    if (end_position > current_position) {
-      SetAfterSegmentPosition(current_position,
-                              end_position - current_position);
-    }
-    return;
-  }
-
-  // Reset the widths to hide the segments.
-  SetBeforeSegmentPosition(0, 0);
-  SetAfterSegmentPosition(0, 0);
-}
-
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.h
index f05c823f..2ad8a7ac 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlTimelineElement.h
@@ -5,7 +5,7 @@
 #ifndef MediaControlTimelineElement_h
 #define MediaControlTimelineElement_h
 
-#include "modules/media_controls/elements/MediaControlSliderElement.h"
+#include "modules/media_controls/elements/MediaControlInputElement.h"
 #include "modules/media_controls/elements/MediaControlTimelineMetrics.h"
 
 namespace blink {
@@ -13,7 +13,7 @@
 class Event;
 class MediaControlsImpl;
 
-class MediaControlTimelineElement final : public MediaControlSliderElement {
+class MediaControlTimelineElement final : public MediaControlInputElement {
  public:
   explicit MediaControlTimelineElement(MediaControlsImpl&);
 
@@ -40,12 +40,7 @@
   // simplicity; deliberately ignores pinch zoom's pageScaleFactor).
   int TimelineWidth();
 
-  void RenderBarSegments();
-
   MediaControlTimelineMetrics metrics_;
-
-  double current_time_;
-  double duration_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
index 1a8b828..6d17362a 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlToggleClosedCaptionsButtonElement.cpp
@@ -31,7 +31,6 @@
   bool captions_visible = MediaElement().TextTracksVisible();
   SetDisplayType(captions_visible ? kMediaHideClosedCaptionsButton
                                   : kMediaShowClosedCaptionsButton);
-  SetClass("visible", captions_visible);
 }
 
 WebLocalizedString::Name
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.cpp b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.cpp
index ecd583e8..16956ff1 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.cpp
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.cpp
@@ -5,6 +5,7 @@
 #include "modules/media_controls/elements/MediaControlVolumeSliderElement.h"
 
 #include "core/HTMLNames.h"
+#include "core/InputTypeNames.h"
 #include "core/dom/events/Event.h"
 #include "core/html/HTMLMediaElement.h"
 #include "core/layout/LayoutObject.h"
@@ -16,10 +17,12 @@
 
 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(
     MediaControlsImpl& media_controls)
-    : MediaControlSliderElement(media_controls, kMediaVolumeSlider) {
+    : MediaControlInputElement(media_controls, kMediaVolumeSlider) {
+  EnsureUserAgentShadowRoot();
+  setType(InputTypeNames::range);
+  setAttribute(HTMLNames::stepAttr, "any");
   setAttribute(HTMLNames::maxAttr, "1");
   SetShadowPseudoId(AtomicString("-webkit-media-controls-volume-slider"));
-  SetVolumeInternal(MediaElement().volume());
 }
 
 void MediaControlVolumeSliderElement::SetVolume(double volume) {
@@ -27,7 +30,8 @@
     return;
 
   setValue(String::Number(volume));
-  SetVolumeInternal(volume);
+  if (LayoutObject* layout_object = this->GetLayoutObject())
+    layout_object->SetShouldDoFullPaintInvalidation();
 }
 
 bool MediaControlVolumeSliderElement::WillRespondToMouseMoveEvents() {
@@ -73,15 +77,11 @@
     double volume = value().ToDouble();
     MediaElement().setVolume(volume);
     MediaElement().setMuted(false);
-    SetVolumeInternal(volume);
+    if (LayoutObject* layout_object = this->GetLayoutObject())
+      layout_object->SetShouldDoFullPaintInvalidation();
   }
 }
 
-void MediaControlVolumeSliderElement::SetVolumeInternal(double volume) {
-  SetupBarSegments();
-  SetBeforeSegmentPosition(0, int(volume * 100));
-}
-
 bool MediaControlVolumeSliderElement::KeepEventInNode(Event* event) {
   return MediaControlElementsHelper::IsUserInteractionEventForSlider(
       event, GetLayoutObject());
diff --git a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.h b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.h
index 29d4f96..b7dc4ed8 100644
--- a/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.h
+++ b/third_party/WebKit/Source/modules/media_controls/elements/MediaControlVolumeSliderElement.h
@@ -5,14 +5,14 @@
 #ifndef MediaControlVolumeSliderElement_h
 #define MediaControlVolumeSliderElement_h
 
-#include "modules/media_controls/elements/MediaControlSliderElement.h"
+#include "modules/media_controls/elements/MediaControlInputElement.h"
 
 namespace blink {
 
 class Event;
 class MediaControlsImpl;
 
-class MediaControlVolumeSliderElement final : public MediaControlSliderElement {
+class MediaControlVolumeSliderElement final : public MediaControlInputElement {
  public:
   explicit MediaControlVolumeSliderElement(MediaControlsImpl&);
 
@@ -31,7 +31,6 @@
  private:
   void DefaultEventHandler(Event*) override;
   bool KeepEventInNode(Event*) override;
-  void SetVolumeInternal(double);
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/modules/media_controls/resources/mediaControls.css b/third_party/WebKit/Source/modules/media_controls/resources/mediaControls.css
index e770228..5df35b7 100644
--- a/third_party/WebKit/Source/modules/media_controls/resources/mediaControls.css
+++ b/third_party/WebKit/Source/modules/media_controls/resources/mediaControls.css
@@ -106,14 +106,8 @@
     bottom: 0px;
 }
 
-audio::-webkit-media-controls-mute-button,
-video::-webkit-media-controls-mute-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_sound_not_muted.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+audio::-webkit-media-controls-mute-button, video::-webkit-media-controls-mute-button {
+    -webkit-appearance: media-mute-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -125,12 +119,6 @@
     color: inherit;
 }
 
-audio::-webkit-media-controls-mute-button.muted,
-video::-webkit-media-controls-mute-button.muted {
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_sound_muted.png) 1x);
-}
-
 audio::-webkit-media-controls-overlay-enclosure {
     display: none;
 }
@@ -153,12 +141,7 @@
 }
 
 video::-webkit-media-controls-overlay-play-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_overlay_play.png) 1x);
-    background-size: 48px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: media-overlay-play-button;
     display: flex;
     position: absolute;
     top: 0;
@@ -203,13 +186,7 @@
 }
 
 video::-internal-media-remoting-cast-icon {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaremoting_cast.png) 1x,
-      url(default_200_percent/mediaremoting_cast.png) 2x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-remoting-cast-icon;
     display: flex;
     position: absolute;
     margin: 0px;
@@ -266,12 +243,7 @@
 }
 
 video::-internal-media-controls-overlay-cast-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_overlay_cast_off.png) 1x);
-    background-size: cover;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-overlay-cast-off-button;
     display: flex;
     position: absolute;
     top: 8px;
@@ -286,19 +258,8 @@
     transition: opacity 0.3s;
 }
 
-video::-internal-media-controls-overlay-cast-button.on {
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_overlay_cast_on.png) 1x);
-}
-
-audio::-webkit-media-controls-play-button,
-video::-webkit-media-controls-play-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_pause.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+audio::-webkit-media-controls-play-button, video::-webkit-media-controls-play-button {
+    -webkit-appearance: media-play-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -310,12 +271,6 @@
     color: inherit;
 }
 
-audio::-webkit-media-controls-play-button.pause,
-video::-webkit-media-controls-play-button.pause {
-  background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_play.png) 1x);
-}
-
 audio::-webkit-media-controls-timeline-container, video::-webkit-media-controls-timeline-container {
     -webkit-appearance: media-controls-background;
     display: flex;
@@ -376,9 +331,8 @@
     text-decoration: none;
 }
 
-audio::-webkit-media-controls-timeline,
-video::-webkit-media-controls-timeline {
-    -webkit-appearance: none;
+audio::-webkit-media-controls-timeline, video::-webkit-media-controls-timeline {
+    -webkit-appearance: media-slider;
     display: flex;
     flex: 1 1 auto;
     height: 2px;
@@ -386,16 +340,16 @@
     /* Leave 6px on either side for the thumb.  Use margin so that
      * the slider doesn't extend into it.  We also add 12px border.
      */
-    margin: 0 18px;
+    padding: 0;
+    margin: 0 18px 0 18px;
     background-color: transparent;
     min-width: 25px;
     border: initial;
     color: inherit;
 }
 
-audio::-webkit-media-controls-volume-slider,
-video::-webkit-media-controls-volume-slider {
-    -webkit-appearance: none;
+audio::-webkit-media-controls-volume-slider, video::-webkit-media-controls-volume-slider {
+    -webkit-appearance: media-volume-slider;
     display: flex;
     /* The 1.9 value was empirically chosen to match old-flexbox behaviour
      * and be aesthetically pleasing.
@@ -407,83 +361,44 @@
      * than padding so that the slider doesn't extend into it.  We also
      * leave an addition 12px margin.
      */
-    margin: 0 18px;
+    padding: 0;
+    margin: 0 18px 0 18px;
     background-color: transparent;
     min-width: 25px;
     border: initial;
     color: inherit;
+}
+
+/* FIXME these shouldn't use special pseudoShadowIds, but nicer rules.
+   https://code.google.com/p/chromium/issues/detail?id=112508
+   https://bugs.webkit.org/show_bug.cgi?id=62218
+*/
+input[type="range" i]::-webkit-media-slider-container {
+    display: flex;
+    align-items: center;
+    flex-direction: row; /* This property is updated by C++ code. */
     box-sizing: border-box;
-}
-
-/**
- * Segmented Track
- */
-
-div.-internal-media-controls-segmented-track {
-    margin: 0 -18px 0 -18px;
-    position: relative;
-}
-
-div.-internal-media-controls-segmented-track .-internal-track-segment-background {
-    width: auto;
-    position: absolute;
-    background: #dadada;
+    /** this positions the slider thumb for both time and volume. */
     height: 2px;
-    margin-top: -1px;
-    left: 18px;
-    right: 18px;
-    top: 50%;
+    width: 100%;
+    background-color: transparent; /* Background drawing is managed by C++ code to draw ranges. */
 }
 
-div.-internal-media-controls-segmented-track .-internal-track-segment-highlight-before,
-div.-internal-media-controls-segmented-track .-internal-track-segment-highlight-after {
-    height: auto;
-    position: absolute;
-    top: 50%;
-    bottom: 0;
-    z-index: 1;
-    height: 2px;
-    margin-top: -1px;
+/* The negative right margin causes the track to overflow its container. */
+input[type="range" i]::-webkit-media-slider-container > div {
+    margin-right: -18px;  /* box is 36px wide, get to the middle */
+    margin-left:  -18px;
 }
 
-div.-internal-media-controls-segmented-track .-internal-track-segment-highlight-before {
-    background-color: #4285f4;
+input[type="range" i]::-webkit-media-slider-thumb {
+    box-sizing: border-box;
+    width: 48px;
+    height: 48px;
+    padding: 0px;
 }
 
-div.-internal-media-controls-segmented-track .-internal-track-segment-highlight-after {
-    background-color: #5a5a5a;
-}
-
-/**
- * Track Thumb
- */
-
-input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb,
-input[pseudo="-webkit-media-controls-volume-slider" i]::-webkit-slider-thumb {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_slider_thumb.png) 1x);
-    background-size: 12px;
-    background-repeat: no-repeat;
-    background-position: center center;
-
-    height: 36px;
-    z-index: 2;
-    width: 36px;
-    margin: 0;
-    padding: 0;
-    top: -18px;
-    position: absolute;
-}
-
-audio::-webkit-media-controls-fullscreen-button,
-video::-webkit-media-controls-fullscreen-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_enter_fullscreen.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+audio::-webkit-media-controls-fullscreen-button, video::-webkit-media-controls-fullscreen-button {
+    -webkit-appearance: media-enter-fullscreen-button;
     display: flex;
     flex: none;
     overflow: hidden;
@@ -496,19 +411,8 @@
     color: inherit;
 }
 
-audio::-webkit-media-controls-fullscreen-button.fullscreen,
-video::-webkit-media-controls-fullscreen-button.fullscreen {
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_exit_fullscreen.png) 1x);
-}
-
 audio::-internal-media-controls-cast-button, video::-internal-media-controls-cast-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_cast_off.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-cast-off-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -522,23 +426,12 @@
     color: inherit;
 }
 
-audio::-internal-media-controls-cast-button.on,
-video::-internal-media-controls-cast-button.on {
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_cast_on.png) 1x);
-}
-
 audio::-webkit-media-controls-toggle-closed-captions-button {
     display: none;
 }
 
 video::-webkit-media-controls-toggle-closed-captions-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_closedcaption_disabled.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: media-toggle-closed-captions-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -552,11 +445,6 @@
     color: inherit;
 }
 
-video::-webkit-media-controls-toggle-closed-captions-button.visible {
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_closedcaption.png) 1x);
-}
-
 video::-internal-media-controls-text-track-list, video::-internal-media-controls-overflow-menu-list, audio::-internal-media-controls-overflow-menu-list {
     position: absolute;
     bottom: 4px;
@@ -589,12 +477,7 @@
 }
 
 video::-internal-media-controls-text-track-list-item-input {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_trackselection_checkmark.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-track-selection-checkmark;
     visibility: hidden;
     left: 0;
     vertical-align: middle;
@@ -609,12 +492,7 @@
 }
 
 video::-internal-media-controls-text-track-list-kind-captions {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_closedcaptions_icon.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-closed-captions-icon;
     height: 20px;
     width: 20px;
     margin-left: 10px;
@@ -622,12 +500,7 @@
 }
 
 video::-internal-media-controls-text-track-list-kind-subtitles {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_subtitles_icon.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-subtitles-icon;
     height: 20px;
     width: 20px;
     margin-left: 10px;
@@ -635,12 +508,7 @@
 }
 
 video::-internal-media-controls-overflow-button, audio::-internal-media-controls-overflow-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_overflow_menu.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-overflow-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -655,12 +523,7 @@
 }
 
 video::-internal-media-controls-download-button, audio::-internal-media-controls-download-button {
-    -webkit-appearance: none;
-    background-image: -webkit-image-set(
-      url(default_100_percent/mediaplayer_download.png) 1x);
-    background-size: 32px;
-    background-repeat: no-repeat;
-    background-position: center center;
+    -webkit-appearance: -internal-media-download-button;
     display: flex;
     flex: none;
     box-sizing: border-box;
@@ -755,18 +618,3 @@
 video::cue(i) {
     font-style: italic;
 }
-
-.not-loaded input[pseudo="-webkit-media-controls-play-button"],
-.not-loaded input[pseudo="-webkit-media-controls-mute-button"],
-.not-loaded input[pseudo="-webkit-media-controls-overlay-play-button"],
-.not-loaded input[pseudo="-webkit-media-controls-fullscreen-button"],
-.not-loaded input[pseudo="-internal-media-controls-download-button"],
-.not-loaded input[pseudo="-webkit-media-controls-timeline" i],
-.not-loaded input[pseudo="-webkit-media-controls-volume-slider" i] {
-    opacity: 0.4;
-}
-
-.not-loaded input[pseudo="-webkit-media-controls-timeline" i]::-webkit-slider-thumb,
-.not-loaded input[pseudo="-webkit-media-controls-volume-slider" i]::-webkit-slider-thumb {
-    display: none;
-}
diff --git a/third_party/WebKit/Source/modules/media_controls/resources/media_controls_resources.grd b/third_party/WebKit/Source/modules/media_controls/resources/media_controls_resources.grd
index c0e1c82..ec3c11b 100644
--- a/third_party/WebKit/Source/modules/media_controls/resources/media_controls_resources.grd
+++ b/third_party/WebKit/Source/modules/media_controls/resources/media_controls_resources.grd
@@ -30,10 +30,10 @@
       <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_OVERFLOW_MENU_ICON" file="mediaplayer_overflow_menu.png" />
       <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_DOWNLOAD_ICON" file="mediaplayer_download.png" />
       <structure type="chrome_scaled_image" name="IDR_MEDIAPLAYER_SUBTITLES_ICON" file="mediaplayer_subtitles_icon.png" />
-      <structure type="chrome_html" name="IDR_UASTYLE_MEDIA_CONTROLS_CSS" file="mediaControls.css" flattenhtml="true" />
     </structures>
     <includes>
-      <include name="IDR_UASTYLE_MEDIA_CONTROLS_ANDROID_CSS" file="mediaControlsAndroid.css" type="BINDATA" compress="gzip" />
+      <include name="IDR_UASTYLE_MEDIA_CONTROLS_ANDROID_CSS" file="mediaControlsAndroid.css" type="chrome_html" compress="gzip" />
+      <include name="IDR_UASTYLE_MEDIA_CONTROLS_CSS" file="mediaControls.css" type="chrome_html" compress="gzip" />
     </includes>
   </release>
 </grit>
diff --git a/third_party/WebKit/Source/modules/serviceworkers/OWNERS b/third_party/WebKit/Source/modules/serviceworkers/OWNERS
index f52d0c3d..299b6b92 100644
--- a/third_party/WebKit/Source/modules/serviceworkers/OWNERS
+++ b/third_party/WebKit/Source/modules/serviceworkers/OWNERS
@@ -1,12 +1,4 @@
-dominicc@chromium.org
-falken@chromium.org
-horo@chromium.org
-jsbell@chromium.org
-kinuko@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 # TEAM: worker-dev@chromium.org
 # COMPONENT: Blink>ServiceWorker
diff --git a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
index 635e12d2..905809e7 100644
--- a/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/DecodingImageGenerator.cpp
@@ -116,13 +116,13 @@
   TRACE_EVENT1("blink", "DecodingImageGenerator::getPixels", "frame index",
                static_cast<int>(frame_index));
 
-  // Implementation doesn't support scaling yet, so make sure we're not given a
-  // different size.
-  // TODO(vmpstr): Implement support for supported sizes.
-  if (dst_info.dimensions() != GetSkImageInfo().dimensions()) {
+  // Implementation only supports decoding to a supported size.
+  if (dst_info.dimensions() != GetSupportedDecodeSize(dst_info.dimensions())) {
     return false;
   }
 
+  // TODO(vmpstr): We could do the color type conversion here by getting N32
+  // colortype decode first, and then converting to whatever was requested.
   if (dst_info.colorType() != kN32_SkColorType) {
     return false;
   }
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
index 723bc92..f465756 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.cpp
@@ -150,9 +150,10 @@
   TRACE_EVENT1("blink", "ImageFrameGenerator::decodeAndScale", "frame index",
                static_cast<int>(index));
 
-  // This implementation does not support scaling so check the requested size.
+  // This implementation does not support arbitrary scaling so check the
+  // requested size.
   SkISize scaled_size = SkISize::Make(info.width(), info.height());
-  DCHECK(full_size_ == scaled_size);
+  CHECK(GetSupportedDecodeSize(scaled_size) == scaled_size);
 
   // It is okay to allocate ref-counted ExternalMemoryAllocator on the stack,
   // because 1) it contains references to memory that will be invalid after
@@ -232,13 +233,13 @@
   // Lock the mutex, so only one thread can use the decoder at once.
   MutexLocker lock(decode_mutex_);
   const bool resume_decoding = ImageDecodingStore::Instance().LockDecoder(
-      this, full_size_, alpha_option, &decoder);
+      this, scaled_size, alpha_option, &decoder);
   DCHECK(!resume_decoding || decoder);
 
   bool used_external_allocator = false;
   ImageFrame* current_frame =
       Decode(data, all_data_received, index, &decoder, allocator, alpha_option,
-             used_external_allocator);
+             scaled_size, used_external_allocator);
 
   if (!decoder)
     return SkBitmap();
@@ -259,10 +260,10 @@
     return SkBitmap();
   }
 
-  SkBitmap full_size_bitmap = current_frame->Bitmap();
-  DCHECK_EQ(full_size_bitmap.width(), full_size_.width());
-  DCHECK_EQ(full_size_bitmap.height(), full_size_.height());
-  SetHasAlpha(index, !full_size_bitmap.isOpaque());
+  SkBitmap scaled_size_bitmap = current_frame->Bitmap();
+  DCHECK_EQ(scaled_size_bitmap.width(), scaled_size.width());
+  DCHECK_EQ(scaled_size_bitmap.height(), scaled_size.height());
+  SetHasAlpha(index, !scaled_size_bitmap.isOpaque());
 
   // Free as much memory as possible.  For single-frame images, we can
   // just delete the decoder entirely if they use the external allocator.
@@ -294,7 +295,7 @@
                                                  std::move(decoder_container));
   }
 
-  return full_size_bitmap;
+  return scaled_size_bitmap;
 }
 
 void ImageFrameGenerator::SetHasAlpha(size_t index, bool has_alpha) {
@@ -314,6 +315,7 @@
                                         ImageDecoder** decoder,
                                         SkBitmap::Allocator& allocator,
                                         ImageDecoder::AlphaOption alpha_option,
+                                        const SkISize& scaled_size,
                                         bool& used_external_allocator) {
 #if DCHECK_IS_ON()
   DCHECK(decode_mutex_.Locked());
@@ -327,12 +329,14 @@
   bool should_call_set_data = true;
   if (!*decoder) {
     new_decoder = true;
+    // TODO(vmpstr): The factory is only used for tests. We can convert all
+    // calls to use a factory so that we don't need to worry about this call.
     if (image_decoder_factory_)
       *decoder = image_decoder_factory_->Create().release();
 
     if (!*decoder) {
       *decoder = ImageDecoder::Create(data, all_data_received, alpha_option,
-                                      decoder_color_behavior_)
+                                      decoder_color_behavior_, scaled_size)
                      .release();
       // The newly created decoder just grabbed the data.  No need to reset it.
       should_call_set_data = false;
diff --git a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
index b4e2c767..951c84c 100644
--- a/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
+++ b/third_party/WebKit/Source/platform/graphics/ImageFrameGenerator.h
@@ -143,6 +143,7 @@
                      ImageDecoder**,
                      SkBitmap::Allocator& external_allocator,
                      ImageDecoder::AlphaOption,
+                     const SkISize& scaled_size,
                      bool& used_external_allocator);
 
   const SkISize full_size_;
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
index dedb36a..3b129f19 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp
@@ -69,14 +69,22 @@
     RefPtr<SegmentReader> data,
     bool data_complete,
     AlphaOption alpha_option,
-    const ColorBehavior& color_behavior) {
+    const ColorBehavior& color_behavior,
+    const SkISize& desired_size) {
   // At least kLongestSignatureLength bytes are needed to sniff the signature.
   if (data->size() < kLongestSignatureLength)
     return nullptr;
 
-  const size_t max_decoded_bytes =
-      Platform::Current() ? Platform::Current()->MaxDecodedImageBytes()
-                          : kNoDecodedImageByteLimit;
+  size_t max_decoded_bytes = Platform::Current()
+                                 ? Platform::Current()->MaxDecodedImageBytes()
+                                 : kNoDecodedImageByteLimit;
+  if (!desired_size.isEmpty()) {
+    static const size_t kBytesPerPixels = 4;
+    size_t requested_decoded_bytes =
+        kBytesPerPixels * desired_size.width() * desired_size.height();
+    DCHECK(requested_decoded_bytes <= max_decoded_bytes);
+    max_decoded_bytes = requested_decoded_bytes;
+  }
 
   // Access the first kLongestSignatureLength chars to sniff the signature.
   // (note: FastSharedBufferReader only makes a copy if the bytes are segmented)
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
index d713a2a..25b88d6c 100644
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.h
@@ -92,17 +92,20 @@
   // we can't sniff a supported type from the provided data (possibly
   // because there isn't enough data yet).
   // Sets |max_decoded_bytes_| to Platform::MaxImageDecodedBytes().
-  static std::unique_ptr<ImageDecoder> Create(RefPtr<SegmentReader> data,
-                                              bool data_complete,
-                                              AlphaOption,
-                                              const ColorBehavior&);
+  static std::unique_ptr<ImageDecoder> Create(
+      RefPtr<SegmentReader> data,
+      bool data_complete,
+      AlphaOption,
+      const ColorBehavior&,
+      const SkISize& desired_size = SkISize::MakeEmpty());
   static std::unique_ptr<ImageDecoder> Create(
       RefPtr<SharedBuffer> data,
       bool data_complete,
       AlphaOption alpha_option,
-      const ColorBehavior& color_behavior) {
+      const ColorBehavior& color_behavior,
+      const SkISize& desired_size = SkISize::MakeEmpty()) {
     return Create(SegmentReader::CreateFromSharedBuffer(std::move(data)),
-                  data_complete, alpha_option, color_behavior);
+                  data_complete, alpha_option, color_behavior, desired_size);
   }
 
   virtual String FilenameExtension() const = 0;
@@ -140,7 +143,7 @@
   bool IsDecodedSizeAvailable() const { return !failed_ && size_available_; }
 
   virtual IntSize Size() const { return size_; }
-  virtual std::vector<SkISize> GetSupportedDecodeSizes() { return {}; };
+  virtual std::vector<SkISize> GetSupportedDecodeSizes() const { return {}; };
 
   // Decoders which downsample images should override this method to
   // return the actual decoded size.
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
index f241ae24..b5f2922e 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.cpp
@@ -394,18 +394,12 @@
   }
 
   // Decode the JPEG data. If |only_size| is specified, then only the size
-  // information will be decoded. If |generate_all_sizes| is specified, this
-  // will generate the sizes for all possible numerators up to the desired
-  // numerator as dictated by the decoder class. Note that |generate_all_sizes|
-  // is only valid if |only_size| is set.
-  bool Decode(bool only_size, bool generate_all_sizes) {
+  // information will be decoded.
+  bool Decode(bool only_size) {
     // We need to do the setjmp here. Otherwise bad things will happen
     if (setjmp(err_.setjmp_buffer))
       return decoder_->SetFailed();
 
-    // Generate all sizes implies we only want the size.
-    DCHECK(!generate_all_sizes || only_size);
-
     J_COLOR_SPACE override_color_space = JCS_UNKNOWN;
     switch (state_) {
       case JPEG_HEADER: {
@@ -444,8 +438,18 @@
 
         // Calculate and set decoded size.
         int max_numerator = decoder_->DesiredScaleNumerator();
-        info_.scale_num = max_numerator;
         info_.scale_denom = g_scale_denomiator;
+
+        if (decoder_->ShouldGenerateAllSizes()) {
+          for (int numerator = 1; numerator <= max_numerator; ++numerator) {
+            info_.scale_num = numerator;
+            jpeg_calc_output_dimensions(&info_);
+            decoder_->AddSupportedDecodeSize(info_.output_width,
+                                             info_.output_height);
+          }
+        }
+
+        info_.scale_num = max_numerator;
         // Scaling caused by running low on memory isn't supported by YUV
         // decoding since YUV decoding is performed on full sized images. At
         // this point, buffers and various image info structs have already been
@@ -456,16 +460,6 @@
         jpeg_calc_output_dimensions(&info_);
         decoder_->SetDecodedSize(info_.output_width, info_.output_height);
 
-        if (generate_all_sizes) {
-          info_.scale_denom = g_scale_denomiator;
-          for (int numerator = 1; numerator <= max_numerator; ++numerator) {
-            info_.scale_num = numerator;
-            jpeg_calc_output_dimensions(&info_);
-            decoder_->AddSupportedDecodeSize(info_.output_width,
-                                             info_.output_height);
-          }
-        }
-
         decoder_->SetOrientation(ReadImageOrientation(Info()));
 
         // Allow color management of the decoded RGBA pixels if possible.
@@ -792,6 +786,10 @@
   return scale_numerator;
 }
 
+bool JPEGImageDecoder::ShouldGenerateAllSizes() const {
+  return supported_decode_sizes_.empty();
+}
+
 bool JPEGImageDecoder::CanDecodeToYUV() {
   // Calling IsSizeAvailable() ensures the reader is created and the output
   // color space is set.
@@ -814,22 +812,13 @@
 }
 
 void JPEGImageDecoder::AddSupportedDecodeSize(unsigned width, unsigned height) {
-#if DCHECK_IS_ON()
-  DCHECK(decoding_all_sizes_);
-#endif
   supported_decode_sizes_.push_back(SkISize::Make(width, height));
 }
 
-std::vector<SkISize> JPEGImageDecoder::GetSupportedDecodeSizes() {
-  if (supported_decode_sizes_.empty()) {
-#if DCHECK_IS_ON()
-    decoding_all_sizes_ = true;
-#endif
-    Decode(true, true);
-#if DCHECK_IS_ON()
-    decoding_all_sizes_ = false;
-#endif
-  }
+std::vector<SkISize> JPEGImageDecoder::GetSupportedDecodeSizes() const {
+  // DCHECK IsDecodedSizeAvailable instead of IsSizeAvailable, since the latter
+  // has side effects of actually doing the decode.
+  DCHECK(IsDecodedSizeAvailable());
   return supported_decode_sizes_;
 }
 
@@ -1035,7 +1024,7 @@
   return decoder->FrameIsDecodedAtIndex(0);
 }
 
-void JPEGImageDecoder::Decode(bool only_size, bool generate_all_sizes) {
+void JPEGImageDecoder::Decode(bool only_size) {
   if (Failed())
     return;
 
@@ -1046,7 +1035,7 @@
 
   // If we couldn't decode the image but have received all the data, decoding
   // has failed.
-  if (!reader_->Decode(only_size, generate_all_sizes) && IsAllDataReceived())
+  if (!reader_->Decode(only_size) && IsAllDataReceived())
     SetFailed();
 
   // If decoding is done or failed, we don't need the JPEGImageReader anymore.
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.h b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.h
index 80c1497..f41422c 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.h
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoder.h
@@ -50,11 +50,12 @@
   bool CanDecodeToYUV() override;
   bool DecodeToYUV() override;
   void SetImagePlanes(std::unique_ptr<ImagePlanes>) override;
-  std::vector<SkISize> GetSupportedDecodeSizes() override;
+  std::vector<SkISize> GetSupportedDecodeSizes() const override;
   bool HasImagePlanes() const { return image_planes_.get(); }
 
   bool OutputScanlines();
   unsigned DesiredScaleNumerator() const;
+  bool ShouldGenerateAllSizes() const;
   void Complete();
 
   void SetOrientation(ImageOrientation orientation) {
@@ -72,15 +73,12 @@
   // Decodes the image.  If |only_size| is true, stops decoding after
   // calculating the image size.  If decoding fails but there is no more
   // data coming, sets the "decode failure" flag.
-  void Decode(bool only_size, bool generate_all_sizes = false);
+  void Decode(bool only_size);
 
   std::unique_ptr<JPEGImageReader> reader_;
   std::unique_ptr<ImagePlanes> image_planes_;
   IntSize decoded_size_;
   std::vector<SkISize> supported_decode_sizes_;
-#if DCHECK_IS_ON()
-  bool decoding_all_sizes_ = false;
-#endif
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
index 6dff6cca..fc335c6 100644
--- a/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
+++ b/third_party/WebKit/Source/platform/image-decoders/jpeg/JPEGImageDecoderTest.cpp
@@ -320,6 +320,8 @@
   std::unique_ptr<ImageDecoder> decoder =
       CreateJPEGDecoder(std::numeric_limits<int>::max());
   decoder->SetData(data.Get(), true);
+  // This will decode the size and needs to be called to avoid DCHECKs
+  ASSERT_TRUE(decoder->IsSizeAvailable());
   std::vector<SkISize> expected_sizes = {
       SkISize::Make(32, 32),   SkISize::Make(64, 64),   SkISize::Make(96, 96),
       SkISize::Make(128, 128), SkISize::Make(160, 160), SkISize::Make(192, 192),
@@ -344,6 +346,8 @@
   std::unique_ptr<ImageDecoder> decoder =
       CreateJPEGDecoder(std::numeric_limits<int>::max());
   decoder->SetData(data.Get(), true);
+  // This will decode the size and needs to be called to avoid DCHECKs
+  ASSERT_TRUE(decoder->IsSizeAvailable());
   std::vector<SkISize> expected_sizes = {
       SkISize::Make(35, 26),   SkISize::Make(69, 52),   SkISize::Make(104, 78),
       SkISize::Make(138, 104), SkISize::Make(172, 130), SkISize::Make(207, 156),
@@ -367,6 +371,8 @@
   // Limit the memory so that 128 would be the largest size possible.
   std::unique_ptr<ImageDecoder> decoder = CreateJPEGDecoder(130 * 130 * 4);
   decoder->SetData(data.Get(), true);
+  // This will decode the size and needs to be called to avoid DCHECKs
+  ASSERT_TRUE(decoder->IsSizeAvailable());
   std::vector<SkISize> expected_sizes = {
       SkISize::Make(32, 32), SkISize::Make(64, 64), SkISize::Make(96, 96),
       SkISize::Make(128, 128)};
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py
deleted file mode 100644
index 4b17b85..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py
+++ /dev/null
@@ -1,2014 +0,0 @@
-"""Beautiful Soup
-Elixir and Tonic
-"The Screen-Scraper's Friend"
-http://www.crummy.com/software/BeautifulSoup/
-
-Beautiful Soup parses a (possibly invalid) XML or HTML document into a
-tree representation. It provides methods and Pythonic idioms that make
-it easy to navigate, search, and modify the tree.
-
-A well-formed XML/HTML document yields a well-formed data
-structure. An ill-formed XML/HTML document yields a correspondingly
-ill-formed data structure. If your document is only locally
-well-formed, you can use this library to find and process the
-well-formed part of it.
-
-Beautiful Soup works with Python 2.2 and up. It has no external
-dependencies, but you'll have more success at converting data to UTF-8
-if you also install these three packages:
-
-* chardet, for auto-detecting character encodings
-  http://chardet.feedparser.org/
-* cjkcodecs and iconv_codec, which add more encodings to the ones supported
-  by stock Python.
-  http://cjkpython.i18n.org/
-
-Beautiful Soup defines classes for two main parsing strategies:
-
- * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific
-   language that kind of looks like XML.
-
- * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid
-   or invalid. This class has web browser-like heuristics for
-   obtaining a sensible parse tree in the face of common HTML errors.
-
-Beautiful Soup also defines a class (UnicodeDammit) for autodetecting
-the encoding of an HTML or XML document, and converting it to
-Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser.
-
-For more than you ever wanted to know about Beautiful Soup, see the
-documentation:
-http://www.crummy.com/software/BeautifulSoup/documentation.html
-
-Here, have some legalese:
-
-Copyright (c) 2004-2010, Leonard Richardson
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-  * Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-
-  * Redistributions in binary form must reproduce the above
-    copyright notice, this list of conditions and the following
-    disclaimer in the documentation and/or other materials provided
-    with the distribution.
-
-  * Neither the name of the the Beautiful Soup Consortium and All
-    Night Kosher Bakery nor the names of its contributors may be
-    used to endorse or promote products derived from this software
-    without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
-CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE, DAMMIT.
-
-"""
-from __future__ import generators
-
-__author__ = "Leonard Richardson (leonardr@segfault.org)"
-__version__ = "3.2.0"
-__copyright__ = "Copyright (c) 2004-2010 Leonard Richardson"
-__license__ = "New-style BSD"
-
-from sgmllib import SGMLParser, SGMLParseError
-import codecs
-import markupbase
-import types
-import re
-import sgmllib
-try:
-  from htmlentitydefs import name2codepoint
-except ImportError:
-  name2codepoint = {}
-try:
-    set
-except NameError:
-    from sets import Set as set
-
-#These hacks make Beautiful Soup able to parse XML with namespaces
-sgmllib.tagfind = re.compile('[a-zA-Z][-_.:a-zA-Z0-9]*')
-markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
-
-DEFAULT_OUTPUT_ENCODING = "utf-8"
-
-def _match_css_class(str):
-    """Build a RE to match the given CSS class."""
-    return re.compile(r"(^|.*\s)%s($|\s)" % str)
-
-# First, the classes that represent markup elements.
-
-class PageElement(object):
-    """Contains the navigational information for some part of the page
-    (either a tag or a piece of text)"""
-
-    def setup(self, parent=None, previous=None):
-        """Sets up the initial relations between this element and
-        other elements."""
-        self.parent = parent
-        self.previous = previous
-        self.next = None
-        self.previousSibling = None
-        self.nextSibling = None
-        if self.parent and self.parent.contents:
-            self.previousSibling = self.parent.contents[-1]
-            self.previousSibling.nextSibling = self
-
-    def replaceWith(self, replaceWith):
-        oldParent = self.parent
-        myIndex = self.parent.index(self)
-        if hasattr(replaceWith, "parent")\
-                  and replaceWith.parent is self.parent:
-            # We're replacing this element with one of its siblings.
-            index = replaceWith.parent.index(replaceWith)
-            if index and index < myIndex:
-                # Furthermore, it comes before this element. That
-                # means that when we extract it, the index of this
-                # element will change.
-                myIndex = myIndex - 1
-        self.extract()
-        oldParent.insert(myIndex, replaceWith)
-
-    def replaceWithChildren(self):
-        myParent = self.parent
-        myIndex = self.parent.index(self)
-        self.extract()
-        reversedChildren = list(self.contents)
-        reversedChildren.reverse()
-        for child in reversedChildren:
-            myParent.insert(myIndex, child)
-
-    def extract(self):
-        """Destructively rips this element out of the tree."""
-        if self.parent:
-            try:
-                del self.parent.contents[self.parent.index(self)]
-            except ValueError:
-                pass
-
-        #Find the two elements that would be next to each other if
-        #this element (and any children) hadn't been parsed. Connect
-        #the two.
-        lastChild = self._lastRecursiveChild()
-        nextElement = lastChild.next
-
-        if self.previous:
-            self.previous.next = nextElement
-        if nextElement:
-            nextElement.previous = self.previous
-        self.previous = None
-        lastChild.next = None
-
-        self.parent = None
-        if self.previousSibling:
-            self.previousSibling.nextSibling = self.nextSibling
-        if self.nextSibling:
-            self.nextSibling.previousSibling = self.previousSibling
-        self.previousSibling = self.nextSibling = None
-        return self
-
-    def _lastRecursiveChild(self):
-        "Finds the last element beneath this object to be parsed."
-        lastChild = self
-        while hasattr(lastChild, 'contents') and lastChild.contents:
-            lastChild = lastChild.contents[-1]
-        return lastChild
-
-    def insert(self, position, newChild):
-        if isinstance(newChild, basestring) \
-            and not isinstance(newChild, NavigableString):
-            newChild = NavigableString(newChild)
-
-        position =  min(position, len(self.contents))
-        if hasattr(newChild, 'parent') and newChild.parent is not None:
-            # We're 'inserting' an element that's already one
-            # of this object's children.
-            if newChild.parent is self:
-                index = self.index(newChild)
-                if index > position:
-                    # Furthermore we're moving it further down the
-                    # list of this object's children. That means that
-                    # when we extract this element, our target index
-                    # will jump down one.
-                    position = position - 1
-            newChild.extract()
-
-        newChild.parent = self
-        previousChild = None
-        if position == 0:
-            newChild.previousSibling = None
-            newChild.previous = self
-        else:
-            previousChild = self.contents[position-1]
-            newChild.previousSibling = previousChild
-            newChild.previousSibling.nextSibling = newChild
-            newChild.previous = previousChild._lastRecursiveChild()
-        if newChild.previous:
-            newChild.previous.next = newChild
-
-        newChildsLastElement = newChild._lastRecursiveChild()
-
-        if position >= len(self.contents):
-            newChild.nextSibling = None
-
-            parent = self
-            parentsNextSibling = None
-            while not parentsNextSibling:
-                parentsNextSibling = parent.nextSibling
-                parent = parent.parent
-                if not parent: # This is the last element in the document.
-                    break
-            if parentsNextSibling:
-                newChildsLastElement.next = parentsNextSibling
-            else:
-                newChildsLastElement.next = None
-        else:
-            nextChild = self.contents[position]
-            newChild.nextSibling = nextChild
-            if newChild.nextSibling:
-                newChild.nextSibling.previousSibling = newChild
-            newChildsLastElement.next = nextChild
-
-        if newChildsLastElement.next:
-            newChildsLastElement.next.previous = newChildsLastElement
-        self.contents.insert(position, newChild)
-
-    def append(self, tag):
-        """Appends the given tag to the contents of this tag."""
-        self.insert(len(self.contents), tag)
-
-    def findNext(self, name=None, attrs={}, text=None, **kwargs):
-        """Returns the first item that matches the given criteria and
-        appears after this Tag in the document."""
-        return self._findOne(self.findAllNext, name, attrs, text, **kwargs)
-
-    def findAllNext(self, name=None, attrs={}, text=None, limit=None,
-                    **kwargs):
-        """Returns all items that match the given criteria and appear
-        after this Tag in the document."""
-        return self._findAll(name, attrs, text, limit, self.nextGenerator,
-                             **kwargs)
-
-    def findNextSibling(self, name=None, attrs={}, text=None, **kwargs):
-        """Returns the closest sibling to this Tag that matches the
-        given criteria and appears after this Tag in the document."""
-        return self._findOne(self.findNextSiblings, name, attrs, text,
-                             **kwargs)
-
-    def findNextSiblings(self, name=None, attrs={}, text=None, limit=None,
-                         **kwargs):
-        """Returns the siblings of this Tag that match the given
-        criteria and appear after this Tag in the document."""
-        return self._findAll(name, attrs, text, limit,
-                             self.nextSiblingGenerator, **kwargs)
-    fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x
-
-    def findPrevious(self, name=None, attrs={}, text=None, **kwargs):
-        """Returns the first item that matches the given criteria and
-        appears before this Tag in the document."""
-        return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
-
-    def findAllPrevious(self, name=None, attrs={}, text=None, limit=None,
-                        **kwargs):
-        """Returns all items that match the given criteria and appear
-        before this Tag in the document."""
-        return self._findAll(name, attrs, text, limit, self.previousGenerator,
-                           **kwargs)
-    fetchPrevious = findAllPrevious # Compatibility with pre-3.x
-
-    def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs):
-        """Returns the closest sibling to this Tag that matches the
-        given criteria and appears before this Tag in the document."""
-        return self._findOne(self.findPreviousSiblings, name, attrs, text,
-                             **kwargs)
-
-    def findPreviousSiblings(self, name=None, attrs={}, text=None,
-                             limit=None, **kwargs):
-        """Returns the siblings of this Tag that match the given
-        criteria and appear before this Tag in the document."""
-        return self._findAll(name, attrs, text, limit,
-                             self.previousSiblingGenerator, **kwargs)
-    fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x
-
-    def findParent(self, name=None, attrs={}, **kwargs):
-        """Returns the closest parent of this Tag that matches the given
-        criteria."""
-        # NOTE: We can't use _findOne because findParents takes a different
-        # set of arguments.
-        r = None
-        l = self.findParents(name, attrs, 1)
-        if l:
-            r = l[0]
-        return r
-
-    def findParents(self, name=None, attrs={}, limit=None, **kwargs):
-        """Returns the parents of this Tag that match the given
-        criteria."""
-
-        return self._findAll(name, attrs, None, limit, self.parentGenerator,
-                             **kwargs)
-    fetchParents = findParents # Compatibility with pre-3.x
-
-    #These methods do the real heavy lifting.
-
-    def _findOne(self, method, name, attrs, text, **kwargs):
-        r = None
-        l = method(name, attrs, text, 1, **kwargs)
-        if l:
-            r = l[0]
-        return r
-
-    def _findAll(self, name, attrs, text, limit, generator, **kwargs):
-        "Iterates over a generator looking for things that match."
-
-        if isinstance(name, SoupStrainer):
-            strainer = name
-        # (Possibly) special case some findAll*(...) searches
-        elif text is None and not limit and not attrs and not kwargs:
-            # findAll*(True)
-            if name is True:
-                return [element for element in generator()
-                        if isinstance(element, Tag)]
-            # findAll*('tag-name')
-            elif isinstance(name, basestring):
-                return [element for element in generator()
-                        if isinstance(element, Tag) and
-                        element.name == name]
-            else:
-                strainer = SoupStrainer(name, attrs, text, **kwargs)
-        # Build a SoupStrainer
-        else:
-            strainer = SoupStrainer(name, attrs, text, **kwargs)
-        results = ResultSet(strainer)
-        g = generator()
-        while True:
-            try:
-                i = g.next()
-            except StopIteration:
-                break
-            if i:
-                found = strainer.search(i)
-                if found:
-                    results.append(found)
-                    if limit and len(results) >= limit:
-                        break
-        return results
-
-    #These Generators can be used to navigate starting from both
-    #NavigableStrings and Tags.
-    def nextGenerator(self):
-        i = self
-        while i is not None:
-            i = i.next
-            yield i
-
-    def nextSiblingGenerator(self):
-        i = self
-        while i is not None:
-            i = i.nextSibling
-            yield i
-
-    def previousGenerator(self):
-        i = self
-        while i is not None:
-            i = i.previous
-            yield i
-
-    def previousSiblingGenerator(self):
-        i = self
-        while i is not None:
-            i = i.previousSibling
-            yield i
-
-    def parentGenerator(self):
-        i = self
-        while i is not None:
-            i = i.parent
-            yield i
-
-    # Utility methods
-    def substituteEncoding(self, str, encoding=None):
-        encoding = encoding or "utf-8"
-        return str.replace("%SOUP-ENCODING%", encoding)
-
-    def toEncoding(self, s, encoding=None):
-        """Encodes an object to a string in some encoding, or to Unicode.
-        ."""
-        if isinstance(s, unicode):
-            if encoding:
-                s = s.encode(encoding)
-        elif isinstance(s, str):
-            if encoding:
-                s = s.encode(encoding)
-            else:
-                s = unicode(s)
-        else:
-            if encoding:
-                s  = self.toEncoding(str(s), encoding)
-            else:
-                s = unicode(s)
-        return s
-
-class NavigableString(unicode, PageElement):
-
-    def __new__(cls, value):
-        """Create a new NavigableString.
-
-        When unpickling a NavigableString, this method is called with
-        the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be
-        passed in to the superclass's __new__ or the superclass won't know
-        how to handle non-ASCII characters.
-        """
-        if isinstance(value, unicode):
-            return unicode.__new__(cls, value)
-        return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
-
-    def __getnewargs__(self):
-        return (NavigableString.__str__(self),)
-
-    def __getattr__(self, attr):
-        """text.string gives you text. This is for backwards
-        compatibility for Navigable*String, but for CData* it lets you
-        get the string without the CData wrapper."""
-        if attr == 'string':
-            return self
-        else:
-            raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
-
-    def __unicode__(self):
-        return str(self).decode(DEFAULT_OUTPUT_ENCODING)
-
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        if encoding:
-            return self.encode(encoding)
-        else:
-            return self
-
-class CData(NavigableString):
-
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        return "<![CDATA[%s]]>" % NavigableString.__str__(self, encoding)
-
-class ProcessingInstruction(NavigableString):
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        output = self
-        if "%SOUP-ENCODING%" in output:
-            output = self.substituteEncoding(output, encoding)
-        return "<?%s?>" % self.toEncoding(output, encoding)
-
-class Comment(NavigableString):
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        return "<!--%s-->" % NavigableString.__str__(self, encoding)
-
-class Declaration(NavigableString):
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        return "<!%s>" % NavigableString.__str__(self, encoding)
-
-class Tag(PageElement):
-
-    """Represents a found HTML tag with its attributes and contents."""
-
-    def _invert(h):
-        "Cheap function to invert a hash."
-        i = {}
-        for k,v in h.items():
-            i[v] = k
-        return i
-
-    XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'",
-                                      "quot" : '"',
-                                      "amp" : "&",
-                                      "lt" : "<",
-                                      "gt" : ">" }
-
-    XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
-
-    def _convertEntities(self, match):
-        """Used in a call to re.sub to replace HTML, XML, and numeric
-        entities with the appropriate Unicode characters. If HTML
-        entities are being converted, any unrecognized entities are
-        escaped."""
-        x = match.group(1)
-        if self.convertHTMLEntities and x in name2codepoint:
-            return unichr(name2codepoint[x])
-        elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
-            if self.convertXMLEntities:
-                return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
-            else:
-                return u'&%s;' % x
-        elif len(x) > 0 and x[0] == '#':
-            # Handle numeric entities
-            if len(x) > 1 and x[1] == 'x':
-                return unichr(int(x[2:], 16))
-            else:
-                return unichr(int(x[1:]))
-
-        elif self.escapeUnrecognizedEntities:
-            return u'&amp;%s;' % x
-        else:
-            return u'&%s;' % x
-
-    def __init__(self, parser, name, attrs=None, parent=None,
-                 previous=None):
-        "Basic constructor."
-
-        # We don't actually store the parser object: that lets extracted
-        # chunks be garbage-collected
-        self.parserClass = parser.__class__
-        self.isSelfClosing = parser.isSelfClosingTag(name)
-        self.name = name
-        if attrs is None:
-            attrs = []
-        elif isinstance(attrs, dict):
-            attrs = attrs.items()
-        self.attrs = attrs
-        self.contents = []
-        self.setup(parent, previous)
-        self.hidden = False
-        self.containsSubstitutions = False
-        self.convertHTMLEntities = parser.convertHTMLEntities
-        self.convertXMLEntities = parser.convertXMLEntities
-        self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
-
-        # Convert any HTML, XML, or numeric entities in the attribute values.
-        convert = lambda(k, val): (k,
-                                   re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
-                                          self._convertEntities,
-                                          val))
-        self.attrs = map(convert, self.attrs)
-
-    def getString(self):
-        if (len(self.contents) == 1
-            and isinstance(self.contents[0], NavigableString)):
-            return self.contents[0]
-
-    def setString(self, string):
-        """Replace the contents of the tag with a string"""
-        self.clear()
-        self.append(string)
-
-    string = property(getString, setString)
-
-    def getText(self, separator=u""):
-        if not len(self.contents):
-            return u""
-        stopNode = self._lastRecursiveChild().next
-        strings = []
-        current = self.contents[0]
-        while current is not stopNode:
-            if isinstance(current, NavigableString):
-                strings.append(current.strip())
-            current = current.next
-        return separator.join(strings)
-
-    text = property(getText)
-
-    def get(self, key, default=None):
-        """Returns the value of the 'key' attribute for the tag, or
-        the value given for 'default' if it doesn't have that
-        attribute."""
-        return self._getAttrMap().get(key, default)
-
-    def clear(self):
-        """Extract all children."""
-        for child in self.contents[:]:
-            child.extract()
-
-    def index(self, element):
-        for i, child in enumerate(self.contents):
-            if child is element:
-                return i
-        raise ValueError("Tag.index: element not in tag")
-
-    def has_key(self, key):
-        return self._getAttrMap().has_key(key)
-
-    def __getitem__(self, key):
-        """tag[key] returns the value of the 'key' attribute for the tag,
-        and throws an exception if it's not there."""
-        return self._getAttrMap()[key]
-
-    def __iter__(self):
-        "Iterating over a tag iterates over its contents."
-        return iter(self.contents)
-
-    def __len__(self):
-        "The length of a tag is the length of its list of contents."
-        return len(self.contents)
-
-    def __contains__(self, x):
-        return x in self.contents
-
-    def __nonzero__(self):
-        "A tag is non-None even if it has no contents."
-        return True
-
-    def __setitem__(self, key, value):
-        """Setting tag[key] sets the value of the 'key' attribute for the
-        tag."""
-        self._getAttrMap()
-        self.attrMap[key] = value
-        found = False
-        for i in range(0, len(self.attrs)):
-            if self.attrs[i][0] == key:
-                self.attrs[i] = (key, value)
-                found = True
-        if not found:
-            self.attrs.append((key, value))
-        self._getAttrMap()[key] = value
-
-    def __delitem__(self, key):
-        "Deleting tag[key] deletes all 'key' attributes for the tag."
-        for item in self.attrs:
-            if item[0] == key:
-                self.attrs.remove(item)
-                #We don't break because bad HTML can define the same
-                #attribute multiple times.
-            self._getAttrMap()
-            if self.attrMap.has_key(key):
-                del self.attrMap[key]
-
-    def __call__(self, *args, **kwargs):
-        """Calling a tag like a function is the same as calling its
-        findAll() method. Eg. tag('a') returns a list of all the A tags
-        found within this tag."""
-        return apply(self.findAll, args, kwargs)
-
-    def __getattr__(self, tag):
-        #print "Getattr %s.%s" % (self.__class__, tag)
-        if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
-            return self.find(tag[:-3])
-        elif tag.find('__') != 0:
-            return self.find(tag)
-        raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
-
-    def __eq__(self, other):
-        """Returns true iff this tag has the same name, the same attributes,
-        and the same contents (recursively) as the given tag.
-
-        NOTE: right now this will return false if two tags have the
-        same attributes in a different order. Should this be fixed?"""
-        if other is self:
-            return True
-        if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other):
-            return False
-        for i in range(0, len(self.contents)):
-            if self.contents[i] != other.contents[i]:
-                return False
-        return True
-
-    def __ne__(self, other):
-        """Returns true iff this tag is not identical to the other tag,
-        as defined in __eq__."""
-        return not self == other
-
-    def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        """Renders this tag as a string."""
-        return self.__str__(encoding)
-
-    def __unicode__(self):
-        return self.__str__(None)
-
-    BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
-                                           + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
-                                           + ")")
-
-    def _sub_entity(self, x):
-        """Used with a regular expression to substitute the
-        appropriate XML entity for an XML special character."""
-        return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"
-
-    def __str__(self, encoding=DEFAULT_OUTPUT_ENCODING,
-                prettyPrint=False, indentLevel=0):
-        """Returns a string or Unicode representation of this tag and
-        its contents. To get Unicode, pass None for encoding.
-
-        NOTE: since Python's HTML parser consumes whitespace, this
-        method is not certain to reproduce the whitespace present in
-        the original string."""
-
-        encodedName = self.toEncoding(self.name, encoding)
-
-        attrs = []
-        if self.attrs:
-            for key, val in self.attrs:
-                fmt = '%s="%s"'
-                if isinstance(val, basestring):
-                    if self.containsSubstitutions and '%SOUP-ENCODING%' in val:
-                        val = self.substituteEncoding(val, encoding)
-
-                    # The attribute value either:
-                    #
-                    # * Contains no embedded double quotes or single quotes.
-                    #   No problem: we enclose it in double quotes.
-                    # * Contains embedded single quotes. No problem:
-                    #   double quotes work here too.
-                    # * Contains embedded double quotes. No problem:
-                    #   we enclose it in single quotes.
-                    # * Embeds both single _and_ double quotes. This
-                    #   can't happen naturally, but it can happen if
-                    #   you modify an attribute value after parsing
-                    #   the document. Now we have a bit of a
-                    #   problem. We solve it by enclosing the
-                    #   attribute in single quotes, and escaping any
-                    #   embedded single quotes to XML entities.
-                    if '"' in val:
-                        fmt = "%s='%s'"
-                        if "'" in val:
-                            # TODO: replace with apos when
-                            # appropriate.
-                            val = val.replace("'", "&squot;")
-
-                    # Now we're okay w/r/t quotes. But the attribute
-                    # value might also contain angle brackets, or
-                    # ampersands that aren't part of entities. We need
-                    # to escape those to XML entities too.
-                    val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
-
-                attrs.append(fmt % (self.toEncoding(key, encoding),
-                                    self.toEncoding(val, encoding)))
-        close = ''
-        closeTag = ''
-        if self.isSelfClosing:
-            close = ' /'
-        else:
-            closeTag = '</%s>' % encodedName
-
-        indentTag, indentContents = 0, 0
-        if prettyPrint:
-            indentTag = indentLevel
-            space = (' ' * (indentTag-1))
-            indentContents = indentTag + 1
-        contents = self.renderContents(encoding, prettyPrint, indentContents)
-        if self.hidden:
-            s = contents
-        else:
-            s = []
-            attributeString = ''
-            if attrs:
-                attributeString = ' ' + ' '.join(attrs)
-            if prettyPrint:
-                s.append(space)
-            s.append('<%s%s%s>' % (encodedName, attributeString, close))
-            if prettyPrint:
-                s.append("\n")
-            s.append(contents)
-            if prettyPrint and contents and contents[-1] != "\n":
-                s.append("\n")
-            if prettyPrint and closeTag:
-                s.append(space)
-            s.append(closeTag)
-            if prettyPrint and closeTag and self.nextSibling:
-                s.append("\n")
-            s = ''.join(s)
-        return s
-
-    def decompose(self):
-        """Recursively destroys the contents of this tree."""
-        self.extract()
-        if len(self.contents) == 0:
-            return
-        current = self.contents[0]
-        while current is not None:
-            next = current.next
-            if isinstance(current, Tag):
-                del current.contents[:]
-            current.parent = None
-            current.previous = None
-            current.previousSibling = None
-            current.next = None
-            current.nextSibling = None
-            current = next
-
-    def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
-        return self.__str__(encoding, True)
-
-    def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
-                       prettyPrint=False, indentLevel=0):
-        """Renders the contents of this tag as a string in the given
-        encoding. If encoding is None, returns a Unicode string.."""
-        s=[]
-        for c in self:
-            text = None
-            if isinstance(c, NavigableString):
-                text = c.__str__(encoding)
-            elif isinstance(c, Tag):
-                s.append(c.__str__(encoding, prettyPrint, indentLevel))
-            if text and prettyPrint:
-                text = text.strip()
-            if text:
-                if prettyPrint:
-                    s.append(" " * (indentLevel-1))
-                s.append(text)
-                if prettyPrint:
-                    s.append("\n")
-        return ''.join(s)
-
-    #Soup methods
-
-    def find(self, name=None, attrs={}, recursive=True, text=None,
-             **kwargs):
-        """Return only the first child of this Tag matching the given
-        criteria."""
-        r = None
-        l = self.findAll(name, attrs, recursive, text, 1, **kwargs)
-        if l:
-            r = l[0]
-        return r
-    findChild = find
-
-    def findAll(self, name=None, attrs={}, recursive=True, text=None,
-                limit=None, **kwargs):
-        """Extracts a list of Tag objects that match the given
-        criteria.  You can specify the name of the Tag and any
-        attributes you want the Tag to have.
-
-        The value of a key-value pair in the 'attrs' map can be a
-        string, a list of strings, a regular expression object, or a
-        callable that takes a string and returns whether or not the
-        string matches for some custom definition of 'matches'. The
-        same is true of the tag name."""
-        generator = self.recursiveChildGenerator
-        if not recursive:
-            generator = self.childGenerator
-        return self._findAll(name, attrs, text, limit, generator, **kwargs)
-    findChildren = findAll
-
-    # Pre-3.x compatibility methods
-    first = find
-    fetch = findAll
-
-    def fetchText(self, text=None, recursive=True, limit=None):
-        return self.findAll(text=text, recursive=recursive, limit=limit)
-
-    def firstText(self, text=None, recursive=True):
-        return self.find(text=text, recursive=recursive)
-
-    #Private methods
-
-    def _getAttrMap(self):
-        """Initializes a map representation of this tag's attributes,
-        if not already initialized."""
-        if not getattr(self, 'attrMap'):
-            self.attrMap = {}
-            for (key, value) in self.attrs:
-                self.attrMap[key] = value
-        return self.attrMap
-
-    #Generator methods
-    def childGenerator(self):
-        # Just use the iterator from the contents
-        return iter(self.contents)
-
-    def recursiveChildGenerator(self):
-        if not len(self.contents):
-            raise StopIteration
-        stopNode = self._lastRecursiveChild().next
-        current = self.contents[0]
-        while current is not stopNode:
-            yield current
-            current = current.next
-
-
-# Next, a couple classes to represent queries and their results.
-class SoupStrainer:
-    """Encapsulates a number of ways of matching a markup element (tag or
-    text)."""
-
-    def __init__(self, name=None, attrs={}, text=None, **kwargs):
-        self.name = name
-        if isinstance(attrs, basestring):
-            kwargs['class'] = _match_css_class(attrs)
-            attrs = None
-        if kwargs:
-            if attrs:
-                attrs = attrs.copy()
-                attrs.update(kwargs)
-            else:
-                attrs = kwargs
-        self.attrs = attrs
-        self.text = text
-
-    def __str__(self):
-        if self.text:
-            return self.text
-        else:
-            return "%s|%s" % (self.name, self.attrs)
-
-    def searchTag(self, markupName=None, markupAttrs={}):
-        found = None
-        markup = None
-        if isinstance(markupName, Tag):
-            markup = markupName
-            markupAttrs = markup
-        callFunctionWithTagData = callable(self.name) \
-                                and not isinstance(markupName, Tag)
-
-        if (not self.name) \
-               or callFunctionWithTagData \
-               or (markup and self._matches(markup, self.name)) \
-               or (not markup and self._matches(markupName, self.name)):
-            if callFunctionWithTagData:
-                match = self.name(markupName, markupAttrs)
-            else:
-                match = True
-                markupAttrMap = None
-                for attr, matchAgainst in self.attrs.items():
-                    if not markupAttrMap:
-                         if hasattr(markupAttrs, 'get'):
-                            markupAttrMap = markupAttrs
-                         else:
-                            markupAttrMap = {}
-                            for k,v in markupAttrs:
-                                markupAttrMap[k] = v
-                    attrValue = markupAttrMap.get(attr)
-                    if not self._matches(attrValue, matchAgainst):
-                        match = False
-                        break
-            if match:
-                if markup:
-                    found = markup
-                else:
-                    found = markupName
-        return found
-
-    def search(self, markup):
-        #print 'looking for %s in %s' % (self, markup)
-        found = None
-        # If given a list of items, scan it for a text element that
-        # matches.
-        if hasattr(markup, "__iter__") \
-                and not isinstance(markup, Tag):
-            for element in markup:
-                if isinstance(element, NavigableString) \
-                       and self.search(element):
-                    found = element
-                    break
-        # If it's a Tag, make sure its name or attributes match.
-        # Don't bother with Tags if we're searching for text.
-        elif isinstance(markup, Tag):
-            if not self.text:
-                found = self.searchTag(markup)
-        # If it's text, make sure the text matches.
-        elif isinstance(markup, NavigableString) or \
-                 isinstance(markup, basestring):
-            if self._matches(markup, self.text):
-                found = markup
-        else:
-            raise Exception, "I don't know how to match against a %s" \
-                  % markup.__class__
-        return found
-
-    def _matches(self, markup, matchAgainst):
-        #print "Matching %s against %s" % (markup, matchAgainst)
-        result = False
-        if matchAgainst is True:
-            result = markup is not None
-        elif callable(matchAgainst):
-            result = matchAgainst(markup)
-        else:
-            #Custom match methods take the tag as an argument, but all
-            #other ways of matching match the tag name as a string.
-            if isinstance(markup, Tag):
-                markup = markup.name
-            if markup and not isinstance(markup, basestring):
-                markup = unicode(markup)
-            #Now we know that chunk is either a string, or None.
-            if hasattr(matchAgainst, 'match'):
-                # It's a regexp object.
-                result = markup and matchAgainst.search(markup)
-            elif hasattr(matchAgainst, '__iter__'): # list-like
-                result = markup in matchAgainst
-            elif hasattr(matchAgainst, 'items'):
-                result = markup.has_key(matchAgainst)
-            elif matchAgainst and isinstance(markup, basestring):
-                if isinstance(markup, unicode):
-                    matchAgainst = unicode(matchAgainst)
-                else:
-                    matchAgainst = str(matchAgainst)
-
-            if not result:
-                result = matchAgainst == markup
-        return result
-
-class ResultSet(list):
-    """A ResultSet is just a list that keeps track of the SoupStrainer
-    that created it."""
-    def __init__(self, source):
-        list.__init__([])
-        self.source = source
-
-# Now, some helper functions.
-
-def buildTagMap(default, *args):
-    """Turns a list of maps, lists, or scalars into a single map.
-    Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and
-    NESTING_RESET_TAGS maps out of lists and partial maps."""
-    built = {}
-    for portion in args:
-        if hasattr(portion, 'items'):
-            #It's a map. Merge it.
-            for k,v in portion.items():
-                built[k] = v
-        elif hasattr(portion, '__iter__'): # is a list
-            #It's a list. Map each item to the default.
-            for k in portion:
-                built[k] = default
-        else:
-            #It's a scalar. Map it to the default.
-            built[portion] = default
-    return built
-
-# Now, the parser classes.
-
-class BeautifulStoneSoup(Tag, SGMLParser):
-
-    """This class contains the basic parser and search code. It defines
-    a parser that knows nothing about tag behavior except for the
-    following:
-
-      You can't close a tag without closing all the tags it encloses.
-      That is, "<foo><bar></foo>" actually means
-      "<foo><bar></bar></foo>".
-
-    [Another possible explanation is "<foo><bar /></foo>", but since
-    this class defines no SELF_CLOSING_TAGS, it will never use that
-    explanation.]
-
-    This class is useful for parsing XML or made-up markup languages,
-    or when BeautifulSoup makes an assumption counter to what you were
-    expecting."""
-
-    SELF_CLOSING_TAGS = {}
-    NESTABLE_TAGS = {}
-    RESET_NESTING_TAGS = {}
-    QUOTE_TAGS = {}
-    PRESERVE_WHITESPACE_TAGS = []
-
-    MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),
-                       lambda x: x.group(1) + ' />'),
-                      (re.compile('<!\s+([^<>]*)>'),
-                       lambda x: '<!' + x.group(1) + '>')
-                      ]
-
-    ROOT_TAG_NAME = u'[document]'
-
-    HTML_ENTITIES = "html"
-    XML_ENTITIES = "xml"
-    XHTML_ENTITIES = "xhtml"
-    # TODO: This only exists for backwards-compatibility
-    ALL_ENTITIES = XHTML_ENTITIES
-
-    # Used when determining whether a text node is all whitespace and
-    # can be replaced with a single space. A text node that contains
-    # fancy Unicode spaces (usually non-breaking) should be left
-    # alone.
-    STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, }
-
-    def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
-                 markupMassage=True, smartQuotesTo=XML_ENTITIES,
-                 convertEntities=None, selfClosingTags=None, isHTML=False):
-        """The Soup object is initialized as the 'root tag', and the
-        provided markup (which can be a string or a file-like object)
-        is fed into the underlying parser.
-
-        sgmllib will process most bad HTML, and the BeautifulSoup
-        class has some tricks for dealing with some HTML that kills
-        sgmllib, but Beautiful Soup can nonetheless choke or lose data
-        if your data uses self-closing tags or declarations
-        incorrectly.
-
-        By default, Beautiful Soup uses regexes to sanitize input,
-        avoiding the vast majority of these problems. If the problems
-        don't apply to you, pass in False for markupMassage, and
-        you'll get better performance.
-
-        The default parser massage techniques fix the two most common
-        instances of invalid HTML that choke sgmllib:
-
-         <br/> (No space between name of closing tag and tag close)
-         <! --Comment--> (Extraneous whitespace in declaration)
-
-        You can pass in a custom list of (RE object, replace method)
-        tuples to get Beautiful Soup to scrub your input the way you
-        want."""
-
-        self.parseOnlyThese = parseOnlyThese
-        self.fromEncoding = fromEncoding
-        self.smartQuotesTo = smartQuotesTo
-        self.convertEntities = convertEntities
-        # Set the rules for how we'll deal with the entities we
-        # encounter
-        if self.convertEntities:
-            # It doesn't make sense to convert encoded characters to
-            # entities even while you're converting entities to Unicode.
-            # Just convert it all to Unicode.
-            self.smartQuotesTo = None
-            if convertEntities == self.HTML_ENTITIES:
-                self.convertXMLEntities = False
-                self.convertHTMLEntities = True
-                self.escapeUnrecognizedEntities = True
-            elif convertEntities == self.XHTML_ENTITIES:
-                self.convertXMLEntities = True
-                self.convertHTMLEntities = True
-                self.escapeUnrecognizedEntities = False
-            elif convertEntities == self.XML_ENTITIES:
-                self.convertXMLEntities = True
-                self.convertHTMLEntities = False
-                self.escapeUnrecognizedEntities = False
-        else:
-            self.convertXMLEntities = False
-            self.convertHTMLEntities = False
-            self.escapeUnrecognizedEntities = False
-
-        self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
-        SGMLParser.__init__(self)
-
-        if hasattr(markup, 'read'):        # It's a file-type object.
-            markup = markup.read()
-        self.markup = markup
-        self.markupMassage = markupMassage
-        try:
-            self._feed(isHTML=isHTML)
-        except StopParsing:
-            pass
-        self.markup = None                 # The markup can now be GCed
-
-    def convert_charref(self, name):
-        """This method fixes a bug in Python's SGMLParser."""
-        try:
-            n = int(name)
-        except ValueError:
-            return
-        if not 0 <= n <= 127 : # ASCII ends at 127, not 255
-            return
-        return self.convert_codepoint(n)
-
-    def _feed(self, inDocumentEncoding=None, isHTML=False):
-        # Convert the document to Unicode.
-        markup = self.markup
-        if isinstance(markup, unicode):
-            if not hasattr(self, 'originalEncoding'):
-                self.originalEncoding = None
-        else:
-            dammit = UnicodeDammit\
-                     (markup, [self.fromEncoding, inDocumentEncoding],
-                      smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
-            markup = dammit.unicode
-            self.originalEncoding = dammit.originalEncoding
-            self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
-        if markup:
-            if self.markupMassage:
-                if not hasattr(self.markupMassage, "__iter__"):
-                    self.markupMassage = self.MARKUP_MASSAGE
-                for fix, m in self.markupMassage:
-                    markup = fix.sub(m, markup)
-                # TODO: We get rid of markupMassage so that the
-                # soup object can be deepcopied later on. Some
-                # Python installations can't copy regexes. If anyone
-                # was relying on the existence of markupMassage, this
-                # might cause problems.
-                del(self.markupMassage)
-        self.reset()
-
-        SGMLParser.feed(self, markup)
-        # Close out any unfinished strings and close all the open tags.
-        self.endData()
-        while self.currentTag.name != self.ROOT_TAG_NAME:
-            self.popTag()
-
-    def __getattr__(self, methodName):
-        """This method routes method call requests to either the SGMLParser
-        superclass or the Tag superclass, depending on the method name."""
-        #print "__getattr__ called on %s.%s" % (self.__class__, methodName)
-
-        if methodName.startswith('start_') or methodName.startswith('end_') \
-               or methodName.startswith('do_'):
-            return SGMLParser.__getattr__(self, methodName)
-        elif not methodName.startswith('__'):
-            return Tag.__getattr__(self, methodName)
-        else:
-            raise AttributeError
-
-    def isSelfClosingTag(self, name):
-        """Returns true iff the given string is the name of a
-        self-closing tag according to this parser."""
-        return self.SELF_CLOSING_TAGS.has_key(name) \
-               or self.instanceSelfClosingTags.has_key(name)
-
-    def reset(self):
-        Tag.__init__(self, self, self.ROOT_TAG_NAME)
-        self.hidden = 1
-        SGMLParser.reset(self)
-        self.currentData = []
-        self.currentTag = None
-        self.tagStack = []
-        self.quoteStack = []
-        self.pushTag(self)
-
-    def popTag(self):
-        tag = self.tagStack.pop()
-
-        #print "Pop", tag.name
-        if self.tagStack:
-            self.currentTag = self.tagStack[-1]
-        return self.currentTag
-
-    def pushTag(self, tag):
-        #print "Push", tag.name
-        if self.currentTag:
-            self.currentTag.contents.append(tag)
-        self.tagStack.append(tag)
-        self.currentTag = self.tagStack[-1]
-
-    def endData(self, containerClass=NavigableString):
-        if self.currentData:
-            currentData = u''.join(self.currentData)
-            if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
-                not set([tag.name for tag in self.tagStack]).intersection(
-                    self.PRESERVE_WHITESPACE_TAGS)):
-                if '\n' in currentData:
-                    currentData = '\n'
-                else:
-                    currentData = ' '
-            self.currentData = []
-            if self.parseOnlyThese and len(self.tagStack) <= 1 and \
-                   (not self.parseOnlyThese.text or \
-                    not self.parseOnlyThese.search(currentData)):
-                return
-            o = containerClass(currentData)
-            o.setup(self.currentTag, self.previous)
-            if self.previous:
-                self.previous.next = o
-            self.previous = o
-            self.currentTag.contents.append(o)
-
-
-    def _popToTag(self, name, inclusivePop=True):
-        """Pops the tag stack up to and including the most recent
-        instance of the given tag. If inclusivePop is false, pops the tag
-        stack up to but *not* including the most recent instqance of
-        the given tag."""
-        #print "Popping to %s" % name
-        if name == self.ROOT_TAG_NAME:
-            return
-
-        numPops = 0
-        mostRecentTag = None
-        for i in range(len(self.tagStack)-1, 0, -1):
-            if name == self.tagStack[i].name:
-                numPops = len(self.tagStack)-i
-                break
-        if not inclusivePop:
-            numPops = numPops - 1
-
-        for i in range(0, numPops):
-            mostRecentTag = self.popTag()
-        return mostRecentTag
-
-    def _smartPop(self, name):
-
-        """We need to pop up to the previous tag of this type, unless
-        one of this tag's nesting reset triggers comes between this
-        tag and the previous tag of this type, OR unless this tag is a
-        generic nesting trigger and another generic nesting trigger
-        comes between this tag and the previous tag of this type.
-
-        Examples:
-         <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'.
-         <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'.
-         <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'.
-
-         <li><ul><li> *<li>* should pop to 'ul', not the first 'li'.
-         <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr'
-         <td><tr><td> *<td>* should pop to 'tr', not the first 'td'
-        """
-
-        nestingResetTriggers = self.NESTABLE_TAGS.get(name)
-        isNestable = nestingResetTriggers != None
-        isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
-        popTo = None
-        inclusive = True
-        for i in range(len(self.tagStack)-1, 0, -1):
-            p = self.tagStack[i]
-            if (not p or p.name == name) and not isNestable:
-                #Non-nestable tags get popped to the top or to their
-                #last occurance.
-                popTo = name
-                break
-            if (nestingResetTriggers is not None
-                and p.name in nestingResetTriggers) \
-                or (nestingResetTriggers is None and isResetNesting
-                    and self.RESET_NESTING_TAGS.has_key(p.name)):
-
-                #If we encounter one of the nesting reset triggers
-                #peculiar to this tag, or we encounter another tag
-                #that causes nesting to reset, pop up to but not
-                #including that tag.
-                popTo = p.name
-                inclusive = False
-                break
-            p = p.parent
-        if popTo:
-            self._popToTag(popTo, inclusive)
-
-    def unknown_starttag(self, name, attrs, selfClosing=0):
-        #print "Start tag %s: %s" % (name, attrs)
-        if self.quoteStack:
-            #This is not a real tag.
-            #print "<%s> is not real!" % name
-            attrs = ''.join([' %s="%s"' % (x, y) for x, y in attrs])
-            self.handle_data('<%s%s>' % (name, attrs))
-            return
-        self.endData()
-
-        if not self.isSelfClosingTag(name) and not selfClosing:
-            self._smartPop(name)
-
-        if self.parseOnlyThese and len(self.tagStack) <= 1 \
-               and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
-            return
-
-        tag = Tag(self, name, attrs, self.currentTag, self.previous)
-        if self.previous:
-            self.previous.next = tag
-        self.previous = tag
-        self.pushTag(tag)
-        if selfClosing or self.isSelfClosingTag(name):
-            self.popTag()
-        if name in self.QUOTE_TAGS:
-            #print "Beginning quote (%s)" % name
-            self.quoteStack.append(name)
-            self.literal = 1
-        return tag
-
-    def unknown_endtag(self, name):
-        #print "End tag %s" % name
-        if self.quoteStack and self.quoteStack[-1] != name:
-            #This is not a real end tag.
-            #print "</%s> is not real!" % name
-            self.handle_data('</%s>' % name)
-            return
-        self.endData()
-        self._popToTag(name)
-        if self.quoteStack and self.quoteStack[-1] == name:
-            self.quoteStack.pop()
-            self.literal = (len(self.quoteStack) > 0)
-
-    def handle_data(self, data):
-        self.currentData.append(data)
-
-    def _toStringSubclass(self, text, subclass):
-        """Adds a certain piece of text to the tree as a NavigableString
-        subclass."""
-        self.endData()
-        self.handle_data(text)
-        self.endData(subclass)
-
-    def handle_pi(self, text):
-        """Handle a processing instruction as a ProcessingInstruction
-        object, possibly one with a %SOUP-ENCODING% slot into which an
-        encoding will be plugged later."""
-        if text[:3] == "xml":
-            text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
-        self._toStringSubclass(text, ProcessingInstruction)
-
-    def handle_comment(self, text):
-        "Handle comments as Comment objects."
-        self._toStringSubclass(text, Comment)
-
-    def handle_charref(self, ref):
-        "Handle character references as data."
-        if self.convertEntities:
-            data = unichr(int(ref))
-        else:
-            data = '&#%s;' % ref
-        self.handle_data(data)
-
-    def handle_entityref(self, ref):
-        """Handle entity references as data, possibly converting known
-        HTML and/or XML entity references to the corresponding Unicode
-        characters."""
-        data = None
-        if self.convertHTMLEntities:
-            try:
-                data = unichr(name2codepoint[ref])
-            except KeyError:
-                pass
-
-        if not data and self.convertXMLEntities:
-                data = self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
-
-        if not data and self.convertHTMLEntities and \
-            not self.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
-                # TODO: We've got a problem here. We're told this is
-                # an entity reference, but it's not an XML entity
-                # reference or an HTML entity reference. Nonetheless,
-                # the logical thing to do is to pass it through as an
-                # unrecognized entity reference.
-                #
-                # Except: when the input is "&carol;" this function
-                # will be called with input "carol". When the input is
-                # "AT&T", this function will be called with input
-                # "T". We have no way of knowing whether a semicolon
-                # was present originally, so we don't know whether
-                # this is an unknown entity or just a misplaced
-                # ampersand.
-                #
-                # The more common case is a misplaced ampersand, so I
-                # escape the ampersand and omit the trailing semicolon.
-                data = "&amp;%s" % ref
-        if not data:
-            # This case is different from the one above, because we
-            # haven't already gone through a supposedly comprehensive
-            # mapping of entities to Unicode characters. We might not
-            # have gone through any mapping at all. So the chances are
-            # very high that this is a real entity, and not a
-            # misplaced ampersand.
-            data = "&%s;" % ref
-        self.handle_data(data)
-
-    def handle_decl(self, data):
-        "Handle DOCTYPEs and the like as Declaration objects."
-        self._toStringSubclass(data, Declaration)
-
-    def parse_declaration(self, i):
-        """Treat a bogus SGML declaration as raw data. Treat a CDATA
-        declaration as a CData object."""
-        j = None
-        if self.rawdata[i:i+9] == '<![CDATA[':
-             k = self.rawdata.find(']]>', i)
-             if k == -1:
-                 k = len(self.rawdata)
-             data = self.rawdata[i+9:k]
-             j = k+3
-             self._toStringSubclass(data, CData)
-        else:
-            try:
-                j = SGMLParser.parse_declaration(self, i)
-            except SGMLParseError:
-                toHandle = self.rawdata[i:]
-                self.handle_data(toHandle)
-                j = i + len(toHandle)
-        return j
-
-class BeautifulSoup(BeautifulStoneSoup):
-
-    """This parser knows the following facts about HTML:
-
-    * Some tags have no closing tag and should be interpreted as being
-      closed as soon as they are encountered.
-
-    * The text inside some tags (ie. 'script') may contain tags which
-      are not really part of the document and which should be parsed
-      as text, not tags. If you want to parse the text as tags, you can
-      always fetch it and parse it explicitly.
-
-    * Tag nesting rules:
-
-      Most tags can't be nested at all. For instance, the occurance of
-      a <p> tag should implicitly close the previous <p> tag.
-
-       <p>Para1<p>Para2
-        should be transformed into:
-       <p>Para1</p><p>Para2
-
-      Some tags can be nested arbitrarily. For instance, the occurance
-      of a <blockquote> tag should _not_ implicitly close the previous
-      <blockquote> tag.
-
-       Alice said: <blockquote>Bob said: <blockquote>Blah
-        should NOT be transformed into:
-       Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah
-
-      Some tags can be nested, but the nesting is reset by the
-      interposition of other tags. For instance, a <tr> tag should
-      implicitly close the previous <tr> tag within the same <table>,
-      but not close a <tr> tag in another table.
-
-       <table><tr>Blah<tr>Blah
-        should be transformed into:
-       <table><tr>Blah</tr><tr>Blah
-        but,
-       <tr>Blah<table><tr>Blah
-        should NOT be transformed into
-       <tr>Blah<table></tr><tr>Blah
-
-    Differing assumptions about tag nesting rules are a major source
-    of problems with the BeautifulSoup class. If BeautifulSoup is not
-    treating as nestable a tag your page author treats as nestable,
-    try ICantBelieveItsBeautifulSoup, MinimalSoup, or
-    BeautifulStoneSoup before writing your own subclass."""
-
-    def __init__(self, *args, **kwargs):
-        if not kwargs.has_key('smartQuotesTo'):
-            kwargs['smartQuotesTo'] = self.HTML_ENTITIES
-        kwargs['isHTML'] = True
-        BeautifulStoneSoup.__init__(self, *args, **kwargs)
-
-    SELF_CLOSING_TAGS = buildTagMap(None,
-                                    ('br' , 'hr', 'input', 'img', 'meta',
-                                    'spacer', 'link', 'frame', 'base', 'col'))
-
-    PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
-
-    QUOTE_TAGS = {'script' : None, 'textarea' : None}
-
-    #According to the HTML standard, each of these inline tags can
-    #contain another tag of the same type. Furthermore, it's common
-    #to actually use these tags this way.
-    NESTABLE_INLINE_TAGS = ('span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
-                            'center')
-
-    #According to the HTML standard, these block tags can contain
-    #another tag of the same type. Furthermore, it's common
-    #to actually use these tags this way.
-    NESTABLE_BLOCK_TAGS = ('blockquote', 'div', 'fieldset', 'ins', 'del')
-
-    #Lists can contain other lists, but there are restrictions.
-    NESTABLE_LIST_TAGS = { 'ol' : [],
-                           'ul' : [],
-                           'li' : ['ul', 'ol'],
-                           'dl' : [],
-                           'dd' : ['dl'],
-                           'dt' : ['dl'] }
-
-    #Tables can contain other tables, but there are restrictions.
-    NESTABLE_TABLE_TAGS = {'table' : [],
-                           'tr' : ['table', 'tbody', 'tfoot', 'thead'],
-                           'td' : ['tr'],
-                           'th' : ['tr'],
-                           'thead' : ['table'],
-                           'tbody' : ['table'],
-                           'tfoot' : ['table'],
-                           }
-
-    NON_NESTABLE_BLOCK_TAGS = ('address', 'form', 'p', 'pre')
-
-    #If one of these tags is encountered, all tags up to the next tag of
-    #this type are popped.
-    RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
-                                     NON_NESTABLE_BLOCK_TAGS,
-                                     NESTABLE_LIST_TAGS,
-                                     NESTABLE_TABLE_TAGS)
-
-    NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
-                                NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
-
-    # Used to detect the charset in a META tag; see start_meta
-    CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
-
-    def start_meta(self, attrs):
-        """Beautiful Soup can detect a charset included in a META tag,
-        try to convert the document to that charset, and re-parse the
-        document from the beginning."""
-        httpEquiv = None
-        contentType = None
-        contentTypeIndex = None
-        tagNeedsEncodingSubstitution = False
-
-        for i in range(0, len(attrs)):
-            key, value = attrs[i]
-            key = key.lower()
-            if key == 'http-equiv':
-                httpEquiv = value
-            elif key == 'content':
-                contentType = value
-                contentTypeIndex = i
-
-        if httpEquiv and contentType: # It's an interesting meta tag.
-            match = self.CHARSET_RE.search(contentType)
-            if match:
-                if (self.declaredHTMLEncoding is not None or
-                    self.originalEncoding == self.fromEncoding):
-                    # An HTML encoding was sniffed while converting
-                    # the document to Unicode, or an HTML encoding was
-                    # sniffed during a previous pass through the
-                    # document, or an encoding was specified
-                    # explicitly and it worked. Rewrite the meta tag.
-                    def rewrite(match):
-                        return match.group(1) + "%SOUP-ENCODING%"
-                    newAttr = self.CHARSET_RE.sub(rewrite, contentType)
-                    attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
-                                               newAttr)
-                    tagNeedsEncodingSubstitution = True
-                else:
-                    # This is our first pass through the document.
-                    # Go through it again with the encoding information.
-                    newCharset = match.group(3)
-                    if newCharset and newCharset != self.originalEncoding:
-                        self.declaredHTMLEncoding = newCharset
-                        self._feed(self.declaredHTMLEncoding)
-                        raise StopParsing
-                    pass
-        tag = self.unknown_starttag("meta", attrs)
-        if tag and tagNeedsEncodingSubstitution:
-            tag.containsSubstitutions = True
-
-class StopParsing(Exception):
-    pass
-
-class ICantBelieveItsBeautifulSoup(BeautifulSoup):
-
-    """The BeautifulSoup class is oriented towards skipping over
-    common HTML errors like unclosed tags. However, sometimes it makes
-    errors of its own. For instance, consider this fragment:
-
-     <b>Foo<b>Bar</b></b>
-
-    This is perfectly valid (if bizarre) HTML. However, the
-    BeautifulSoup class will implicitly close the first b tag when it
-    encounters the second 'b'. It will think the author wrote
-    "<b>Foo<b>Bar", and didn't close the first 'b' tag, because
-    there's no real-world reason to bold something that's already
-    bold. When it encounters '</b></b>' it will close two more 'b'
-    tags, for a grand total of three tags closed instead of two. This
-    can throw off the rest of your document structure. The same is
-    true of a number of other tags, listed below.
-
-    It's much more common for someone to forget to close a 'b' tag
-    than to actually use nested 'b' tags, and the BeautifulSoup class
-    handles the common case. This class handles the not-co-common
-    case: where you can't believe someone wrote what they did, but
-    it's valid HTML and BeautifulSoup screwed up by assuming it
-    wouldn't be."""
-
-    I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
-     ('em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
-      'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
-      'big')
-
-    I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ('noscript',)
-
-    NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
-                                I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
-                                I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
-
-class MinimalSoup(BeautifulSoup):
-    """The MinimalSoup class is for parsing HTML that contains
-    pathologically bad markup. It makes no assumptions about tag
-    nesting, but it does know which tags are self-closing, that
-    <script> tags contain Javascript and should not be parsed, that
-    META tags may contain encoding information, and so on.
-
-    This also makes it better for subclassing than BeautifulStoneSoup
-    or BeautifulSoup."""
-
-    RESET_NESTING_TAGS = buildTagMap('noscript')
-    NESTABLE_TAGS = {}
-
-class BeautifulSOAP(BeautifulStoneSoup):
-    """This class will push a tag with only a single string child into
-    the tag's parent as an attribute. The attribute's name is the tag
-    name, and the value is the string child. An example should give
-    the flavor of the change:
-
-    <foo><bar>baz</bar></foo>
-     =>
-    <foo bar="baz"><bar>baz</bar></foo>
-
-    You can then access fooTag['bar'] instead of fooTag.barTag.string.
-
-    This is, of course, useful for scraping structures that tend to
-    use subelements instead of attributes, such as SOAP messages. Note
-    that it modifies its input, so don't print the modified version
-    out.
-
-    I'm not sure how many people really want to use this class; let me
-    know if you do. Mainly I like the name."""
-
-    def popTag(self):
-        if len(self.tagStack) > 1:
-            tag = self.tagStack[-1]
-            parent = self.tagStack[-2]
-            parent._getAttrMap()
-            if (isinstance(tag, Tag) and len(tag.contents) == 1 and
-                isinstance(tag.contents[0], NavigableString) and
-                not parent.attrMap.has_key(tag.name)):
-                parent[tag.name] = tag.contents[0]
-        BeautifulStoneSoup.popTag(self)
-
-#Enterprise class names! It has come to our attention that some people
-#think the names of the Beautiful Soup parser classes are too silly
-#and "unprofessional" for use in enterprise screen-scraping. We feel
-#your pain! For such-minded folk, the Beautiful Soup Consortium And
-#All-Night Kosher Bakery recommends renaming this file to
-#"RobustParser.py" (or, in cases of extreme enterprisiness,
-#"RobustParserBeanInterface.class") and using the following
-#enterprise-friendly class aliases:
-class RobustXMLParser(BeautifulStoneSoup):
-    pass
-class RobustHTMLParser(BeautifulSoup):
-    pass
-class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
-    pass
-class RobustInsanelyWackAssHTMLParser(MinimalSoup):
-    pass
-class SimplifyingSOAPParser(BeautifulSOAP):
-    pass
-
-######################################################
-#
-# Bonus library: Unicode, Dammit
-#
-# This class forces XML data into a standard format (usually to UTF-8
-# or Unicode).  It is heavily based on code from Mark Pilgrim's
-# Universal Feed Parser. It does not rewrite the XML or HTML to
-# reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi
-# (XML) and BeautifulSoup.start_meta (HTML).
-
-# Autodetects character encodings.
-# Download from http://chardet.feedparser.org/
-try:
-    import chardet
-#    import chardet.constants
-#    chardet.constants._debug = 1
-except ImportError:
-    chardet = None
-
-# cjkcodecs and iconv_codec make Python know about more character encodings.
-# Both are available from http://cjkpython.i18n.org/
-# They're built in if you use Python 2.4.
-try:
-    import cjkcodecs.aliases
-except ImportError:
-    pass
-try:
-    import iconv_codec
-except ImportError:
-    pass
-
-class UnicodeDammit:
-    """A class for detecting the encoding of a *ML document and
-    converting it to a Unicode string. If the source encoding is
-    windows-1252, can replace MS smart quotes with their HTML or XML
-    equivalents."""
-
-    # This dictionary maps commonly seen values for "charset" in HTML
-    # meta tags to the corresponding Python codec names. It only covers
-    # values that aren't in Python's aliases and can't be determined
-    # by the heuristics in find_codec.
-    CHARSET_ALIASES = { "macintosh" : "mac-roman",
-                        "x-sjis" : "shift-jis" }
-
-    def __init__(self, markup, overrideEncodings=[],
-                 smartQuotesTo='xml', isHTML=False):
-        self.declaredHTMLEncoding = None
-        self.markup, documentEncoding, sniffedEncoding = \
-                     self._detectEncoding(markup, isHTML)
-        self.smartQuotesTo = smartQuotesTo
-        self.triedEncodings = []
-        if markup == '' or isinstance(markup, unicode):
-            self.originalEncoding = None
-            self.unicode = unicode(markup)
-            return
-
-        u = None
-        for proposedEncoding in overrideEncodings:
-            u = self._convertFrom(proposedEncoding)
-            if u: break
-        if not u:
-            for proposedEncoding in (documentEncoding, sniffedEncoding):
-                u = self._convertFrom(proposedEncoding)
-                if u: break
-
-        # If no luck and we have auto-detection library, try that:
-        if not u and chardet and not isinstance(self.markup, unicode):
-            u = self._convertFrom(chardet.detect(self.markup)['encoding'])
-
-        # As a last resort, try utf-8 and windows-1252:
-        if not u:
-            for proposed_encoding in ("utf-8", "windows-1252"):
-                u = self._convertFrom(proposed_encoding)
-                if u: break
-
-        self.unicode = u
-        if not u: self.originalEncoding = None
-
-    def _subMSChar(self, orig):
-        """Changes a MS smart quote character to an XML or HTML
-        entity."""
-        sub = self.MS_CHARS.get(orig)
-        if isinstance(sub, tuple):
-            if self.smartQuotesTo == 'xml':
-                sub = '&#x%s;' % sub[1]
-            else:
-                sub = '&%s;' % sub[0]
-        return sub
-
-    def _convertFrom(self, proposed):
-        proposed = self.find_codec(proposed)
-        if not proposed or proposed in self.triedEncodings:
-            return None
-        self.triedEncodings.append(proposed)
-        markup = self.markup
-
-        # Convert smart quotes to HTML if coming from an encoding
-        # that might have them.
-        if self.smartQuotesTo and proposed.lower() in("windows-1252",
-                                                      "iso-8859-1",
-                                                      "iso-8859-2"):
-            markup = re.compile("([\x80-\x9f])").sub \
-                     (lambda(x): self._subMSChar(x.group(1)),
-                      markup)
-
-        try:
-            # print "Trying to convert document to %s" % proposed
-            u = self._toUnicode(markup, proposed)
-            self.markup = u
-            self.originalEncoding = proposed
-        except Exception, e:
-            # print "That didn't work!"
-            # print e
-            return None
-        #print "Correct encoding: %s" % proposed
-        return self.markup
-
-    def _toUnicode(self, data, encoding):
-        '''Given a string and its encoding, decodes the string into Unicode.
-        %encoding is a string recognized by encodings.aliases'''
-
-        # strip Byte Order Mark (if present)
-        if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
-               and (data[2:4] != '\x00\x00'):
-            encoding = 'utf-16be'
-            data = data[2:]
-        elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
-                 and (data[2:4] != '\x00\x00'):
-            encoding = 'utf-16le'
-            data = data[2:]
-        elif data[:3] == '\xef\xbb\xbf':
-            encoding = 'utf-8'
-            data = data[3:]
-        elif data[:4] == '\x00\x00\xfe\xff':
-            encoding = 'utf-32be'
-            data = data[4:]
-        elif data[:4] == '\xff\xfe\x00\x00':
-            encoding = 'utf-32le'
-            data = data[4:]
-        newdata = unicode(data, encoding)
-        return newdata
-
-    def _detectEncoding(self, xml_data, isHTML=False):
-        """Given a document, tries to detect its XML encoding."""
-        xml_encoding = sniffed_xml_encoding = None
-        try:
-            if xml_data[:4] == '\x4c\x6f\xa7\x94':
-                # EBCDIC
-                xml_data = self._ebcdic_to_ascii(xml_data)
-            elif xml_data[:4] == '\x00\x3c\x00\x3f':
-                # UTF-16BE
-                sniffed_xml_encoding = 'utf-16be'
-                xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
-            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
-                     and (xml_data[2:4] != '\x00\x00'):
-                # UTF-16BE with BOM
-                sniffed_xml_encoding = 'utf-16be'
-                xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
-            elif xml_data[:4] == '\x3c\x00\x3f\x00':
-                # UTF-16LE
-                sniffed_xml_encoding = 'utf-16le'
-                xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
-            elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
-                     (xml_data[2:4] != '\x00\x00'):
-                # UTF-16LE with BOM
-                sniffed_xml_encoding = 'utf-16le'
-                xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
-            elif xml_data[:4] == '\x00\x00\x00\x3c':
-                # UTF-32BE
-                sniffed_xml_encoding = 'utf-32be'
-                xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
-            elif xml_data[:4] == '\x3c\x00\x00\x00':
-                # UTF-32LE
-                sniffed_xml_encoding = 'utf-32le'
-                xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
-            elif xml_data[:4] == '\x00\x00\xfe\xff':
-                # UTF-32BE with BOM
-                sniffed_xml_encoding = 'utf-32be'
-                xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
-            elif xml_data[:4] == '\xff\xfe\x00\x00':
-                # UTF-32LE with BOM
-                sniffed_xml_encoding = 'utf-32le'
-                xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
-            elif xml_data[:3] == '\xef\xbb\xbf':
-                # UTF-8 with BOM
-                sniffed_xml_encoding = 'utf-8'
-                xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
-            else:
-                sniffed_xml_encoding = 'ascii'
-                pass
-        except:
-            xml_encoding_match = None
-        xml_encoding_match = re.compile(
-            '^<\?.*encoding=[\'"](.*?)[\'"].*\?>').match(xml_data)
-        if not xml_encoding_match and isHTML:
-            regexp = re.compile('<\s*meta[^>]+charset=([^>]*?)[;\'">]', re.I)
-            xml_encoding_match = regexp.search(xml_data)
-        if xml_encoding_match is not None:
-            xml_encoding = xml_encoding_match.groups()[0].lower()
-            if isHTML:
-                self.declaredHTMLEncoding = xml_encoding
-            if sniffed_xml_encoding and \
-               (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
-                                 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
-                                 'utf-16', 'utf-32', 'utf_16', 'utf_32',
-                                 'utf16', 'u16')):
-                xml_encoding = sniffed_xml_encoding
-        return xml_data, xml_encoding, sniffed_xml_encoding
-
-
-    def find_codec(self, charset):
-        return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
-               or (charset and self._codec(charset.replace("-", ""))) \
-               or (charset and self._codec(charset.replace("-", "_"))) \
-               or charset
-
-    def _codec(self, charset):
-        if not charset: return charset
-        codec = None
-        try:
-            codecs.lookup(charset)
-            codec = charset
-        except (LookupError, ValueError):
-            pass
-        return codec
-
-    EBCDIC_TO_ASCII_MAP = None
-    def _ebcdic_to_ascii(self, s):
-        c = self.__class__
-        if not c.EBCDIC_TO_ASCII_MAP:
-            emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
-                    16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
-                    128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
-                    144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
-                    32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
-                    38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
-                    45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
-                    186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
-                    195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
-                    201,202,106,107,108,109,110,111,112,113,114,203,204,205,
-                    206,207,208,209,126,115,116,117,118,119,120,121,122,210,
-                    211,212,213,214,215,216,217,218,219,220,221,222,223,224,
-                    225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
-                    73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
-                    82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
-                    90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
-                    250,251,252,253,254,255)
-            import string
-            c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
-            ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
-        return s.translate(c.EBCDIC_TO_ASCII_MAP)
-
-    MS_CHARS = { '\x80' : ('euro', '20AC'),
-                 '\x81' : ' ',
-                 '\x82' : ('sbquo', '201A'),
-                 '\x83' : ('fnof', '192'),
-                 '\x84' : ('bdquo', '201E'),
-                 '\x85' : ('hellip', '2026'),
-                 '\x86' : ('dagger', '2020'),
-                 '\x87' : ('Dagger', '2021'),
-                 '\x88' : ('circ', '2C6'),
-                 '\x89' : ('permil', '2030'),
-                 '\x8A' : ('Scaron', '160'),
-                 '\x8B' : ('lsaquo', '2039'),
-                 '\x8C' : ('OElig', '152'),
-                 '\x8D' : '?',
-                 '\x8E' : ('#x17D', '17D'),
-                 '\x8F' : '?',
-                 '\x90' : '?',
-                 '\x91' : ('lsquo', '2018'),
-                 '\x92' : ('rsquo', '2019'),
-                 '\x93' : ('ldquo', '201C'),
-                 '\x94' : ('rdquo', '201D'),
-                 '\x95' : ('bull', '2022'),
-                 '\x96' : ('ndash', '2013'),
-                 '\x97' : ('mdash', '2014'),
-                 '\x98' : ('tilde', '2DC'),
-                 '\x99' : ('trade', '2122'),
-                 '\x9a' : ('scaron', '161'),
-                 '\x9b' : ('rsaquo', '203A'),
-                 '\x9c' : ('oelig', '153'),
-                 '\x9d' : '?',
-                 '\x9e' : ('#x17E', '17E'),
-                 '\x9f' : ('Yuml', ''),}
-
-#######################################################################
-
-
-#By default, act as an HTML pretty-printer.
-if __name__ == '__main__':
-    import sys
-    soup = BeautifulSoup(sys.stdin)
-    print soup.prettify()
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
index 29c52767..7877c8e 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/thirdparty/README.chromium
@@ -16,16 +16,6 @@
 Description: Used to reformat python code via format-webkitpy
 Local Modifications: None
 
-Name: BeautifulSoup - HTML parser
-Short Name: BeautifulSoup
-URL: http://www.crummy.com/software/BeautifulSoup/download/3.x/BeautifulSoup-3.2.1.tar.gz (?)
-Version: 3.2
-License: MIT
-License File: NOT_SHIPPED
-Security Critical: no
-Description: Used during the w3c import, other places
-Local Modifications: None
-
 Name: coverage - code coverage metrics for python
 Short Name: coverage
 URL: http://pypi.python.org/packages/source/c/coverage/coverage-3.5.1.tar.gz#md5=410d4c8155a4dab222f2bc51212d4a24
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py
deleted file mode 100644
index e41f5d9..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser.py
+++ /dev/null
@@ -1,174 +0,0 @@
-# Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above
-#    copyright notice, this list of conditions and the following
-#    disclaimer.
-# 2. Redistributions in binary form must reproduce the above
-#    copyright notice, this list of conditions and the following
-#    disclaimer in the documentation and/or other materials
-#    provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-
-import HTMLParser
-import logging
-import re
-
-from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
-
-
-_log = logging.getLogger(__name__)
-
-
-class TestParser(object):
-
-    def __init__(self, filename, host):
-        self.filename = filename
-        self.host = host
-        self.filesystem = self.host.filesystem
-
-        self.test_doc = None
-        self.ref_doc = None
-        self.load_file(filename)
-
-    def load_file(self, filename, is_ref=False):
-        if self.filesystem.isfile(filename):
-            try:
-                doc = BeautifulSoup(self.filesystem.read_binary_file(filename))
-            except IOError:
-                _log.error('IOError: Failed to read %s', filename)
-                doc = None
-            except HTMLParser.HTMLParseError:
-                # FIXME: Figure out what to do if we can't parse the file.
-                _log.error('HTMLParseError: Failed to parse %s', filename)
-                doc = None
-            except UnicodeEncodeError:
-                _log.error('UnicodeEncodeError while reading %s', filename)
-                doc = None
-        else:
-            if self.filesystem.isdir(filename):
-                # FIXME: Figure out what is triggering this and what to do about it.
-                _log.error('Trying to load %s, which is a directory', filename)
-            doc = None
-
-        if is_ref:
-            self.ref_doc = doc
-        else:
-            self.test_doc = doc
-
-    def analyze_test(self, test_contents=None, ref_contents=None):
-        """Analyzes a file to determine if it's a test, what type of test, and what reference or support files it requires.
-
-        Returns: A dict which can have the properties:
-            "test": test file name.
-            "reference": related reference test file name if this is a reference test.
-            "reference_support_info": extra information about the related reference test and any support files.
-            "jstest": A boolean, whether this is a JS test.
-            If the path doesn't look a test or the given contents are empty,
-            then None is returned.
-        """
-        test_info = None
-
-        if test_contents is None and self.test_doc is None:
-            return test_info
-
-        if test_contents is not None:
-            self.test_doc = BeautifulSoup(test_contents)
-
-        if ref_contents is not None:
-            self.ref_doc = BeautifulSoup(ref_contents)
-
-        # First check if it's a reftest
-        matches = self.reference_links_of_type('match') + self.reference_links_of_type('mismatch')
-        if matches:
-            if len(matches) > 1:
-                # FIXME: Is this actually true? We should fix this.
-                _log.warning('Multiple references are not supported. Importing the first ref defined in %s',
-                             self.filesystem.basename(self.filename))
-
-            try:
-                ref_file = self.filesystem.join(self.filesystem.dirname(self.filename), matches[0]['href'])
-            except KeyError:
-                # FIXME: Figure out what to do w/ invalid test files.
-                _log.error('%s has a reference link but is missing the "href"', self.filesystem)
-                return None
-
-            if self.ref_doc is None:
-                self.load_file(ref_file, True)
-
-            test_info = {'test': self.filename, 'reference': ref_file}
-
-            # If the ref file does not live in the same directory as the test file, check it for support files.
-            test_info['reference_support_info'] = {}
-            if self.filesystem.dirname(ref_file) != self.filesystem.dirname(self.filename):
-                reference_support_files = self.support_files(self.ref_doc)
-                if len(reference_support_files) > 0:
-                    reference_relpath = self.filesystem.relpath(self.filesystem.dirname(
-                        self.filename), self.filesystem.dirname(ref_file)) + self.filesystem.sep
-                    test_info['reference_support_info'] = {'reference_relpath': reference_relpath, 'files': reference_support_files}
-
-        elif self.is_jstest():
-            test_info = {'test': self.filename, 'jstest': True}
-
-        elif re.search(r'[/\\]wpt[/\\]css[/\\]', self.filename):
-            # In the former csswg-test tests, all other files should be manual tests.
-            # This function isn't called for non-test files in support/.
-            test_info = {'test': self.filename}
-
-        elif '-manual.' in self.filesystem.basename(self.filename):
-            # WPT has a naming convention for manual tests.
-            test_info = {'test': self.filename}
-
-        return test_info
-
-    def reference_links_of_type(self, reftest_type):
-        return self.test_doc.findAll(rel=reftest_type)
-
-    def is_jstest(self):
-        """Returns whether the file appears to be a jstest, by searching for usage of W3C-style testharness paths."""
-        return bool(self.test_doc.find(src=re.compile('[\'\"/]?/resources/testharness')))
-
-    def support_files(self, doc):
-        """Searches the file for all paths specified in url()s or src attributes."""
-        support_files = []
-
-        if doc is None:
-            return support_files
-
-        elements_with_src_attributes = doc.findAll(src=re.compile('.*'))
-        elements_with_href_attributes = doc.findAll(href=re.compile('.*'))
-
-        url_pattern = re.compile(r'url\(.*\)')
-        urls = []
-        for url in doc.findAll(text=url_pattern):
-            url = re.search(url_pattern, url)
-            url = re.sub(r'url\([\'\"]?', '', url.group(0))
-            url = re.sub(r'[\'\"]?\)', '', url)
-            urls.append(url)
-
-        src_paths = [src_tag['src'] for src_tag in elements_with_src_attributes]
-        href_paths = [href_tag['href'] for href_tag in elements_with_href_attributes]
-
-        paths = src_paths + href_paths + urls
-        for path in paths:
-            if not path.startswith('http:') and not path.startswith('mailto:'):
-                uri_scheme_pattern = re.compile(r'[A-Za-z][A-Za-z+.-]*:')
-                if not uri_scheme_pattern.match(path):
-                    support_files.append(path)
-
-        return support_files
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser_unittest.py
deleted file mode 100644
index b8d5b06..0000000
--- a/third_party/WebKit/Tools/Scripts/webkitpy/w3c/test_parser_unittest.py
+++ /dev/null
@@ -1,232 +0,0 @@
-# Copyright (C) 2013 Adobe Systems Incorporated. All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above
-#    copyright notice, this list of conditions and the following
-#    disclaimer.
-# 2. Redistributions in binary form must reproduce the above
-#    copyright notice, this list of conditions and the following
-#    disclaimer in the documentation and/or other materials
-#    provided with the distribution.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
-# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
-# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE
-# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
-# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
-# TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
-# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-# SUCH DAMAGE.
-
-import os
-import unittest
-
-from webkitpy.common.host_mock import MockHost
-from webkitpy.common.system.output_capture import OutputCapture
-from webkitpy.w3c.test_parser import TestParser
-
-
-class TestParserTest(unittest.TestCase):
-
-    def test_analyze_test_reftest_one_match(self):
-        test_html = """<head>
-<link rel="match" href="green-box-ref.xht" />
-</head>
-"""
-        test_path = '/some/madeup/path/'
-        parser = TestParser(test_path + 'somefile.html', MockHost())
-        test_info = parser.analyze_test(test_contents=test_html)
-
-        self.assertNotEqual(test_info, None, 'did not find a test')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertTrue('reference' in test_info.keys(), 'did not find a reference file')
-        self.assertTrue(test_info['reference'].startswith(test_path), 'reference path is not correct')
-        self.assertFalse('refsupport' in test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertFalse('jstest' in test_info.keys(), 'test should not have been analyzed as a jstest')
-
-    def test_analyze_test_reftest_multiple_matches(self):
-        test_html = """<head>
-<link rel="match" href="green-box-ref.xht" />
-<link rel="match" href="blue-box-ref.xht" />
-<link rel="match" href="orange-box-ref.xht" />
-</head>
-"""
-        oc = OutputCapture()
-        oc.capture_output()
-        try:
-            test_path = '/some/madeup/path/'
-            parser = TestParser(test_path + 'somefile.html', MockHost())
-            test_info = parser.analyze_test(test_contents=test_html)
-        finally:
-            _, _, logs = oc.restore_output()
-
-        self.assertNotEqual(test_info, None, 'did not find a test')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertTrue('reference' in test_info.keys(), 'did not find a reference file')
-        self.assertTrue(test_info['reference'].startswith(test_path), 'reference path is not correct')
-        self.assertFalse('refsupport' in test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertFalse('jstest' in test_info.keys(), 'test should not have been analyzed as a jstest')
-
-        self.assertEqual(logs, 'Multiple references are not supported. Importing the first ref defined in somefile.html\n')
-
-    def test_analyze_test_reftest_match_and_mismatch(self):
-        test_html = """<head>
-<link rel="match" href="green-box-ref.xht" />
-<link rel="match" href="blue-box-ref.xht" />
-<link rel="mismatch" href="orange-box-notref.xht" />
-</head>
-"""
-        oc = OutputCapture()
-        oc.capture_output()
-
-        try:
-            test_path = '/some/madeup/path/'
-            parser = TestParser(test_path + 'somefile.html', MockHost())
-            test_info = parser.analyze_test(test_contents=test_html)
-        finally:
-            _, _, logs = oc.restore_output()
-
-        self.assertNotEqual(test_info, None, 'did not find a test')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertTrue('reference' in test_info.keys(), 'did not find a reference file')
-        self.assertTrue(test_info['reference'].startswith(test_path), 'reference path is not correct')
-        self.assertFalse('refsupport' in test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertFalse('jstest' in test_info.keys(), 'test should not have been analyzed as a jstest')
-
-        self.assertEqual(logs, 'Multiple references are not supported. Importing the first ref defined in somefile.html\n')
-
-    def test_analyze_test_reftest_with_ref_support_Files(self):
-        """Tests analyze_test() using a reftest that has refers to a
-        reference file outside of the tests directory and the reference
-        file has paths to other support files.
-        """
-
-        test_html = """<html>
-<head>
-<link rel="match" href="../reference/green-box-ref.xht" />
-</head>
-"""
-        ref_html = """<head>
-<link href="support/css/ref-stylesheet.css" rel="stylesheet" type="text/css">
-<style type="text/css">
-    background-image: url("../../support/some-image.png")
-</style>
-</head>
-<body>
-<div><img src="../support/black96x96.png" alt="Image download support must be enabled" /></div>
-</body>
-</html>
-"""
-        test_path = '/some/madeup/path/'
-        parser = TestParser(test_path + 'somefile.html', MockHost())
-        test_info = parser.analyze_test(test_contents=test_html, ref_contents=ref_html)
-
-        self.assertNotEqual(test_info, None, 'did not find a test')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertTrue('reference' in test_info.keys(), 'did not find a reference file')
-        self.assertTrue(test_info['reference'].startswith(test_path), 'reference path is not correct')
-        self.assertTrue('reference_support_info' in test_info.keys(), 'there should be reference_support_info for this test')
-        self.assertEquals(len(test_info['reference_support_info']['files']), 3, 'there should be 3 support files in this reference')
-        self.assertFalse('jstest' in test_info.keys(), 'test should not have been analyzed as a jstest')
-
-    def test_analyze_jstest(self):
-        """Tests analyze_test() using a jstest"""
-
-        test_html = """<head>
-<link href="/resources/testharness.css" rel="stylesheet" type="text/css">
-<script src="/resources/testharness.js"></script>
-</head>
-"""
-        test_path = '/some/madeup/path/'
-        parser = TestParser(test_path + 'somefile.html', MockHost())
-        test_info = parser.analyze_test(test_contents=test_html)
-
-        self.assertNotEqual(test_info, None, 'test_info is None')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertFalse('reference' in test_info.keys(), 'should not have found a reference file')
-        self.assertFalse('refsupport' in test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertTrue('jstest' in test_info.keys(), 'test should be a jstest')
-
-    def test_analyze_wpt_manual_test(self):
-        """Tests analyze_test() with a manual test that is not in csswg-test."""
-
-        test_html = """<html>
-<head>
-<title>CSS Test: DESCRIPTION OF TEST</title>
-<link rel="author" title="NAME_OF_AUTHOR" />
-<style type="text/css"><![CDATA[
-CSS FOR TEST
-]]></style>
-</head>
-<body>
-CONTENT OF TEST
-</body>
-</html>
-"""
-        test_path = '/some/madeup/path/'
-        parser = TestParser(test_path + 'somefile-manual.html', MockHost())
-        test_info = parser.analyze_test(test_contents=test_html)
-
-        self.assertNotEqual(test_info, None, 'test_info is None')
-        self.assertTrue('test' in test_info.keys(), 'did not find a test file')
-        self.assertFalse('reference' in test_info.keys(), 'shold not have found a reference file')
-        self.assertFalse('refsupport' in test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertFalse('jstest' in test_info.keys(), 'test should not be a jstest')
-
-    def test_analyze_non_test_file_returns_none(self):
-        """Tests analyze_test() using a non-test file."""
-
-        parser = TestParser('/some/madeup/path/somefile.html', MockHost())
-        test_info = parser.analyze_test(test_contents='<html>')
-        self.assertIsNone(test_info, 'test should have been skipped')
-
-    def test_analyze_csswg_manual_test(self):
-        """Tests analyze_test() using a test that is neither a reftest or jstest, in csswg-test"""
-
-        test_html = """<html>
-<head>
-<title>CSS Test: DESCRIPTION OF TEST</title>
-<link rel="author" title="NAME_OF_AUTHOR" />
-<style type="text/css"><![CDATA[
-CSS FOR TEST
-]]></style>
-</head>
-<body>
-CONTENT OF TEST
-</body>
-</html>
-"""
-        parser = TestParser('/some/wpt/css/path/somefile.html', MockHost())
-        test_info = parser.analyze_test(test_contents=test_html)
-        self.assertIsNotNone(test_info, 'test_info should not be None')
-        self.assertIn('test', test_info.keys(), 'should find a test file')
-        self.assertNotIn('reference', test_info.keys(), 'shold not have found a reference file')
-        self.assertNotIn('refsupport', test_info.keys(), 'there should be no refsupport files for this test')
-        self.assertNotIn('jstest', test_info.keys(), 'test should not be a jstest')
-
-    def test_analyze_non_html_file(self):
-        """Tests analyze_test() with a file that has no html"""
-        # FIXME: use a mock filesystem
-        parser = TestParser(os.path.join(os.path.dirname(__file__), 'test_parser.py'), MockHost())
-        test_info = parser.analyze_test()
-        self.assertEqual(test_info, None, 'no tests should have been found in this file')
-
-    def test_parser_initialization_non_existent_file(self):
-        parser = TestParser('some/bogus/path.html', MockHost())
-        self.assertEqual(parser.filename, 'some/bogus/path.html')
-        self.assertIsNone(parser.test_doc)
-        self.assertIsNone(parser.ref_doc)
-
-    def test_load_file_with_non_ascii_tags(self):
-        host = MockHost()
-        host.filesystem.files['/some/path.xml'] = '<d\xc3\x98dd></d\xc3\x98dd>'
-        parser = TestParser('/some/path.xml', host)
-        self.assertEqual(parser.filename, '/some/path.xml')
-        self.assertIsNone(parser.test_doc)
diff --git a/third_party/WebKit/public/BUILD.gn b/third_party/WebKit/public/BUILD.gn
index a2cb1f9..331447a 100644
--- a/third_party/WebKit/public/BUILD.gn
+++ b/third_party/WebKit/public/BUILD.gn
@@ -893,7 +893,6 @@
     "platform/modules/offscreencanvas/offscreen_canvas_surface.mojom",
   ]
   deps = [
-    "//cc/ipc:interfaces",
     "//services/viz/public/interfaces",
   ]
 
diff --git a/third_party/WebKit/public/platform/modules/serviceworker/OWNERS b/third_party/WebKit/public/platform/modules/serviceworker/OWNERS
index 4c524b6..4a73d48 100644
--- a/third_party/WebKit/public/platform/modules/serviceworker/OWNERS
+++ b/third_party/WebKit/public/platform/modules/serviceworker/OWNERS
@@ -1,12 +1,4 @@
-dominicc@chromium.org
-falken@chromium.org
-horo@chromium.org
-jsbell@chromium.org
-kinuko@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
diff --git a/third_party/WebKit/public/web/modules/serviceworker/OWNERS b/third_party/WebKit/public/web/modules/serviceworker/OWNERS
index f52d0c3d..299b6b92 100644
--- a/third_party/WebKit/public/web/modules/serviceworker/OWNERS
+++ b/third_party/WebKit/public/web/modules/serviceworker/OWNERS
@@ -1,12 +1,4 @@
-dominicc@chromium.org
-falken@chromium.org
-horo@chromium.org
-jsbell@chromium.org
-kinuko@chromium.org
-mek@chromium.org
-michaeln@chromium.org
-nhiroki@chromium.org
-shimazu@chromium.org
+file://content/browser/service_worker/OWNERS
 
 # TEAM: worker-dev@chromium.org
 # COMPONENT: Blink>ServiceWorker
diff --git a/tools/gritsettings/resource_ids b/tools/gritsettings/resource_ids
index ce0e8ee..ee0116d 100644
--- a/tools/gritsettings/resource_ids
+++ b/tools/gritsettings/resource_ids
@@ -310,7 +310,6 @@
 
   "third_party/WebKit/public/blink_image_resources.grd": {
     "structures": [25300],
-    "includes": [25350],
   },
   "third_party/WebKit/public/blink_resources.grd": {
     "includes": [25400],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index a4fb33d7..05473bb 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -8750,6 +8750,8 @@
   <int value="22" label="Completed with content length mismatch"/>
   <int value="23" label="More bytes received after content length mismatch"/>
   <int value="24" label="No bytes received after content length mismatch"/>
+  <int value="25" label="Target determination requeted"/>
+  <int value="26" label="Target determination completed"/>
 </enum>
 
 <enum name="DownloadDatabaseRecordDroppedType">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 8d026b9..784b3ec 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -83273,6 +83273,14 @@
   </details>
 </histogram>
 
+<histogram name="Tabs.TabsStatsDailyEventInterval"
+    enum="DailyEventIntervalType">
+  <owner>sebmarchand@chromium.org</owner>
+  <summary>
+    Counts how often tab stats daily interval events were fired.
+  </summary>
+</histogram>
+
 <histogram name="TabsApi.RequestedWindowState" enum="RequestedWindowState">
   <owner>afakhry@chromium.org</owner>
   <summary>
diff --git a/tools/perf/benchmark.csv b/tools/perf/benchmark.csv
index c9d0265..2d7cb4a 100644
--- a/tools/perf/benchmark.csv
+++ b/tools/perf/benchmark.csv
@@ -9,6 +9,7 @@
 blink_perf.css,rune@opera.com,
 blink_perf.dom,"jbroman@chromium.org, yukishiino@chromium.org, haraken@chromium.org",
 blink_perf.events,hayato@chromium.org,
+blink_perf.image_decoder,"cblume@chromium.org, reveman@chromium.org",
 blink_perf.layout,eae@chromium.org,
 blink_perf.owp_storage,dmurph@chromium.org,
 blink_perf.paint,wangxianzhu@chromium.org,
diff --git a/tools/perf/benchmarks/blink_perf.py b/tools/perf/benchmarks/blink_perf.py
index e3064c97..6166306 100644
--- a/tools/perf/benchmarks/blink_perf.py
+++ b/tools/perf/benchmarks/blink_perf.py
@@ -431,6 +431,24 @@
     return StoryExpectations()
 
 
+@benchmark.Owner(emails=['cblume@chromium.org',
+                         'reveman@chromium.org'])
+class BlinkPerfImageDecoder(_BlinkPerfBenchmark):
+  tag = 'image_decoder'
+  subdir = 'ImageDecoder'
+
+  def SetExtraBrowserOptions(self, options):
+    options.AppendExtraBrowserArgs([
+        '--enable-blink-features=JSImageDecode',
+    ])
+
+  def GetExpectations(self):
+    class StoryExpectations(story.expectations.StoryExpectations):
+      def SetExpectations(self):
+        pass # Nothing disabled.
+    return StoryExpectations()
+
+
 @benchmark.Owner(emails=['eae@chromium.org'])
 class BlinkPerfLayout(_BlinkPerfBenchmark):
   tag = 'layout'
diff --git a/tools/perf/core/perf_data_generator.py b/tools/perf/core/perf_data_generator.py
index 68b8c10d..2214987 100755
--- a/tools/perf/core/perf_data_generator.py
+++ b/tools/perf/core/perf_data_generator.py
@@ -32,6 +32,7 @@
 
 
 _UNSCHEDULED_TELEMETRY_BENCHMARKS = set([
+    'blink_perf.image_decoder',
   ])
 
 
diff --git a/tools/perf/page_sets/system_health/expectations.py b/tools/perf/page_sets/system_health/expectations.py
index d4e37dd..3775641 100644
--- a/tools/perf/page_sets/system_health/expectations.py
+++ b/tools/perf/page_sets/system_health/expectations.py
@@ -129,6 +129,10 @@
                       'crbug.com/759777')
     self.DisableStory('browse:news:cnn',
                       [expectations.ALL_MAC], 'crbug.com/728576')
+    self.DisableStory('browse:tools:earth', [expectations.ALL_DESKTOP],
+                      'crbug.com/708590')
+    self.DisableStory('browse:tools:maps', [expectations.ALL_DESKTOP],
+                      'crbug.com/712694')
 
 
 # Should only include browse:*:* stories.
@@ -136,6 +140,8 @@
   def SetExpectations(self):
     self.DisableStory('browse:shopping:flipkart', [expectations.ALL_ANDROID],
                       'crbug.com/708300')
+    self.DisableStory('browse:news:cnn', [expectations.ANDROID_NEXUS5X],
+                      'crbug.com/714650')
     self.DisableStory('browse:news:globo', [expectations.ALL_ANDROID],
                       'crbug.com/714650')
     self.DisableStory('browse:news:toi', [expectations.ALL_ANDROID],
diff --git a/ui/android/delegated_frame_host_android.cc b/ui/android/delegated_frame_host_android.cc
index b1e2944..d529496 100644
--- a/ui/android/delegated_frame_host_android.cc
+++ b/ui/android/delegated_frame_host_android.cc
@@ -66,6 +66,10 @@
   DCHECK(client_);
 
   host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+  host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_,
+                                                   "DelegatedFrameHostAndroid");
+#endif
   CreateNewCompositorFrameSinkSupport();
 }
 
diff --git a/ui/aura/local/layer_tree_frame_sink_local.cc b/ui/aura/local/layer_tree_frame_sink_local.cc
index d535bcb4..ec8c5475 100644
--- a/ui/aura/local/layer_tree_frame_sink_local.cc
+++ b/ui/aura/local/layer_tree_frame_sink_local.cc
@@ -19,12 +19,16 @@
 
 LayerTreeFrameSinkLocal::LayerTreeFrameSinkLocal(
     const viz::FrameSinkId& frame_sink_id,
-    viz::HostFrameSinkManager* host_frame_sink_manager)
+    viz::HostFrameSinkManager* host_frame_sink_manager,
+    const std::string& debug_label)
     : cc::LayerTreeFrameSink(nullptr, nullptr, nullptr, nullptr),
       frame_sink_id_(frame_sink_id),
       host_frame_sink_manager_(host_frame_sink_manager),
       weak_factory_(this) {
   host_frame_sink_manager_->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+  host_frame_sink_manager_->SetFrameSinkDebugLabel(frame_sink_id_, debug_label);
+#endif
 }
 
 LayerTreeFrameSinkLocal::~LayerTreeFrameSinkLocal() {
diff --git a/ui/aura/local/layer_tree_frame_sink_local.h b/ui/aura/local/layer_tree_frame_sink_local.h
index 116d30e..54cb0fb 100644
--- a/ui/aura/local/layer_tree_frame_sink_local.h
+++ b/ui/aura/local/layer_tree_frame_sink_local.h
@@ -33,7 +33,8 @@
                                 public viz::HostFrameSinkClient {
  public:
   LayerTreeFrameSinkLocal(const viz::FrameSinkId& frame_sink_id,
-                          viz::HostFrameSinkManager* host_frame_sink_manager);
+                          viz::HostFrameSinkManager* host_frame_sink_manager,
+                          const std::string& debug_label);
   ~LayerTreeFrameSinkLocal() override;
 
   using SurfaceChangedCallback = base::Callback<void(const viz::SurfaceInfo&)>;
diff --git a/ui/aura/local/window_port_local.cc b/ui/aura/local/window_port_local.cc
index fc60d26d..4de9b299 100644
--- a/ui/aura/local/window_port_local.cc
+++ b/ui/aura/local/window_port_local.cc
@@ -119,7 +119,8 @@
       aura::Env::GetInstance()->context_factory_private();
   frame_sink_id_ = context_factory_private->AllocateFrameSinkId();
   auto frame_sink = base::MakeUnique<LayerTreeFrameSinkLocal>(
-      frame_sink_id_, context_factory_private->GetHostFrameSinkManager());
+      frame_sink_id_, context_factory_private->GetHostFrameSinkManager(),
+      window_->GetName());
   frame_sink->SetSurfaceChangedCallback(base::Bind(
       &WindowPortLocal::OnSurfaceChanged, weak_factory_.GetWeakPtr()));
   frame_sink_ = frame_sink->GetWeakPtr();
diff --git a/ui/compositor/compositor.cc b/ui/compositor/compositor.cc
index d950439..152fa80c 100644
--- a/ui/compositor/compositor.cc
+++ b/ui/compositor/compositor.cc
@@ -81,6 +81,10 @@
     auto* host_frame_sink_manager =
         context_factory_private_->GetHostFrameSinkManager();
     host_frame_sink_manager->RegisterFrameSinkId(frame_sink_id_, this);
+#if DCHECK_IS_ON()
+    host_frame_sink_manager->SetFrameSinkDebugLabel(frame_sink_id_,
+                                                    "Compositor");
+#endif
   }
   root_web_layer_ = cc::Layer::Create();
 
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
index df8e642..8d8672c2 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.cc
@@ -43,8 +43,7 @@
 }
 
 void GbmSurfaceless::QueueOverlayPlane(const OverlayPlane& plane) {
-  if (plane.buffer->RequiresGlFinish())
-    is_on_external_drm_device_ = true;
+  is_on_external_drm_device_ = plane.buffer->RequiresGlFinish();
   planes_.push_back(plane);
 }
 
@@ -120,10 +119,11 @@
   // TODO(dcastagna): Remove the following workaround once we get explicit sync
   // on Intel.
   // We can not rely on implicit sync on external devices (crbug.com/692508).
-  // NOTE: When on external devices, |is_on_external_drm_device_| is set to true
-  // after the first plane is enqueued in QueueOverlayPlane, that is called from
+  // NOTE: When on internal devices, |is_on_external_drm_device_| is set to true
+  // by default conservatively, and it is correctly computed after the first
+  // plane is enqueued in QueueOverlayPlane, that is called from
   // GbmSurfaceless::SubmitFrame.
-  // This means |is_on_external_drm_device_| could be incorrectly set to false
+  // This means |is_on_external_drm_device_| could be incorrectly set to true
   // the first time we're testing it.
   if (rely_on_implicit_sync_ && !is_on_external_drm_device_) {
     frame->ready = true;
diff --git a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
index 823e0ed..db5491c 100644
--- a/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
+++ b/ui/ozone/platform/drm/gpu/gbm_surfaceless.h
@@ -95,7 +95,9 @@
   bool last_swap_buffers_result_ = true;
   bool swap_buffers_pending_ = false;
   bool rely_on_implicit_sync_ = false;
-  bool is_on_external_drm_device_ = false;
+  // Conservatively assume we begin on a device that requires
+  // explicit synchronization.
+  bool is_on_external_drm_device_ = true;
 
   base::WeakPtrFactory<GbmSurfaceless> weak_factory_;
 
diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc
index 346a7ce..65ca3d5 100644
--- a/ui/wm/core/window_animations.cc
+++ b/ui/wm/core/window_animations.cc
@@ -321,6 +321,10 @@
   ScopedHidingAnimationSettings hiding_settings(window);
   hiding_settings.layer_animation_settings()->SetAnimationMetricsReporter(
       g_reporter_hide.Pointer());
+  // Render surface caching may not provide a benefit when animating the opacity
+  // of a single layer.
+  if (!window->layer()->children().empty())
+    hiding_settings.layer_animation_settings()->CacheRenderSurface();
   base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
   if (duration > base::TimeDelta())
     hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);