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 620ee13..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..9b7e447 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 bbe3fac..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 dcc6677..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 929bf7e..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 08fc1f5..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 b398d42..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..789b9b7 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..9b88c10 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 3482ab9..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 56b6be02..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..8e7fa27 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..fa9dce1 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 81b956e..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 82a8409..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..8d940ea 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..62ee585 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 c35725e..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..c334b17 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..6d42733 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