Reland "[BlinkGenPropertyTrees] Associate each cc::KeyframeModel with ElementId"

This relands the commit 4391edc08203d66f87950a080cbfbfcb2f2b9d22 from
https://chromium-review.googlesource.com/c/chromium/src/+/1297305

The only difference is that the composited-filter-animation test has been made
asynchronous and to wait for the actual time when full saturation should be visible.

TBR=pdr@chromium.org

Cq-Include-Trybots: luci.chromium.try:linux-blink-gen-property-trees;luci.chromium.try:linux_layout_tests_slimming_paint_v2;master.tryserver.blink:linux_trusty_blink_rel
Bug: 896549
Change-Id: Idd597082b7ebd97d277f0e196236a155a4c0351d
Reviewed-on: https://chromium-review.googlesource.com/c/1347784
Reviewed-by: Robert Flack <flackr@chromium.org>
Commit-Queue: Robert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#610494}
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc
index 2af7060..f5d216c 100644
--- a/cc/animation/element_animations.cc
+++ b/cc/animation/element_animations.cc
@@ -22,6 +22,22 @@
 
 namespace cc {
 
+namespace {
+
+// After BlinkGenPropertyTrees, the targeted ElementId depends on the property
+// being mutated. If an ElementId is set on the KeyframeModel, we should apply
+// the mutation to the specific element.
+// TODO(flackr): Remove ElementId from ElementAnimations once all element
+// tracking is done on the KeyframeModel - https://crbug.com/900241
+ElementId CalculateTargetElementId(const ElementAnimations* element_animations,
+                                   const KeyframeModel* keyframe_model) {
+  if (keyframe_model->element_id())
+    return keyframe_model->element_id();
+  return element_animations->element_id();
+}
+
+}  // namespace
+
 scoped_refptr<ElementAnimations> ElementAnimations::Create() {
   return base::WrapRefCounted(new ElementAnimations());
 }
@@ -262,9 +278,9 @@
   DCHECK(keyframe_model->target_property_id() == TargetProperty::OPACITY);
   opacity = base::ClampToRange(opacity, 0.0f, 1.0f);
   if (KeyframeModelAffectsActiveElements(keyframe_model))
-    OnOpacityAnimated(ElementListType::ACTIVE, opacity);
+    OnOpacityAnimated(ElementListType::ACTIVE, opacity, keyframe_model);
   if (KeyframeModelAffectsPendingElements(keyframe_model))
-    OnOpacityAnimated(ElementListType::PENDING, opacity);
+    OnOpacityAnimated(ElementListType::PENDING, opacity, keyframe_model);
 }
 
 void ElementAnimations::NotifyClientFilterAnimated(
@@ -272,9 +288,9 @@
     int target_property_id,
     KeyframeModel* keyframe_model) {
   if (KeyframeModelAffectsActiveElements(keyframe_model))
-    OnFilterAnimated(ElementListType::ACTIVE, filters);
+    OnFilterAnimated(ElementListType::ACTIVE, filters, keyframe_model);
   if (KeyframeModelAffectsPendingElements(keyframe_model))
-    OnFilterAnimated(ElementListType::PENDING, filters);
+    OnFilterAnimated(ElementListType::PENDING, filters, keyframe_model);
 }
 
 void ElementAnimations::NotifyClientTransformOperationsAnimated(
@@ -283,9 +299,9 @@
     KeyframeModel* keyframe_model) {
   gfx::Transform transform = operations.Apply();
   if (KeyframeModelAffectsActiveElements(keyframe_model))
-    OnTransformAnimated(ElementListType::ACTIVE, transform);
+    OnTransformAnimated(ElementListType::ACTIVE, transform, keyframe_model);
   if (KeyframeModelAffectsPendingElements(keyframe_model))
-    OnTransformAnimated(ElementListType::PENDING, transform);
+    OnTransformAnimated(ElementListType::PENDING, transform, keyframe_model);
 }
 
 void ElementAnimations::NotifyClientScrollOffsetAnimated(
@@ -293,9 +309,11 @@
     int target_property_id,
     KeyframeModel* keyframe_model) {
   if (KeyframeModelAffectsActiveElements(keyframe_model))
-    OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset);
+    OnScrollOffsetAnimated(ElementListType::ACTIVE, scroll_offset,
+                           keyframe_model);
   if (KeyframeModelAffectsPendingElements(keyframe_model))
-    OnScrollOffsetAnimated(ElementListType::PENDING, scroll_offset);
+    OnScrollOffsetAnimated(ElementListType::PENDING, scroll_offset,
+                           keyframe_model);
 }
 
 void ElementAnimations::UpdateClientAnimationState() {
@@ -395,40 +413,48 @@
 }
 
 void ElementAnimations::OnFilterAnimated(ElementListType list_type,
-                                         const FilterOperations& filters) {
-  DCHECK(element_id());
+                                         const FilterOperations& filters,
+                                         KeyframeModel* keyframe_model) {
+  ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
+  DCHECK(target_element_id);
   DCHECK(animation_host());
   DCHECK(animation_host()->mutator_host_client());
   animation_host()->mutator_host_client()->SetElementFilterMutated(
-      element_id(), list_type, filters);
+      target_element_id, list_type, filters);
 }
 
 void ElementAnimations::OnOpacityAnimated(ElementListType list_type,
-                                          float opacity) {
-  DCHECK(element_id());
+                                          float opacity,
+                                          KeyframeModel* keyframe_model) {
+  ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
+  DCHECK(target_element_id);
   DCHECK(animation_host());
   DCHECK(animation_host()->mutator_host_client());
   animation_host()->mutator_host_client()->SetElementOpacityMutated(
-      element_id(), list_type, opacity);
+      target_element_id, list_type, opacity);
 }
 
 void ElementAnimations::OnTransformAnimated(ElementListType list_type,
-                                            const gfx::Transform& transform) {
-  DCHECK(element_id());
+                                            const gfx::Transform& transform,
+                                            KeyframeModel* keyframe_model) {
+  ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
+  DCHECK(target_element_id);
   DCHECK(animation_host());
   DCHECK(animation_host()->mutator_host_client());
   animation_host()->mutator_host_client()->SetElementTransformMutated(
-      element_id(), list_type, transform);
+      target_element_id, list_type, transform);
 }
 
 void ElementAnimations::OnScrollOffsetAnimated(
     ElementListType list_type,
-    const gfx::ScrollOffset& scroll_offset) {
-  DCHECK(element_id());
+    const gfx::ScrollOffset& scroll_offset,
+    KeyframeModel* keyframe_model) {
+  ElementId target_element_id = CalculateTargetElementId(this, keyframe_model);
+  DCHECK(target_element_id);
   DCHECK(animation_host());
   DCHECK(animation_host()->mutator_host_client());
   animation_host()->mutator_host_client()->SetElementScrollOffsetMutated(
-      element_id(), list_type, scroll_offset);
+      target_element_id, list_type, scroll_offset);
 }
 
 gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const {
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h
index c7e68bb..7c51dc7 100644
--- a/cc/animation/element_animations.h
+++ b/cc/animation/element_animations.h
@@ -171,12 +171,17 @@
   ~ElementAnimations() override;
 
   void OnFilterAnimated(ElementListType list_type,
-                        const FilterOperations& filters);
-  void OnOpacityAnimated(ElementListType list_type, float opacity);
+                        const FilterOperations& filters,
+                        KeyframeModel* keyframe_model);
+  void OnOpacityAnimated(ElementListType list_type,
+                         float opacity,
+                         KeyframeModel* keyframe_model);
   void OnTransformAnimated(ElementListType list_type,
-                           const gfx::Transform& transform);
+                           const gfx::Transform& transform,
+                           KeyframeModel* keyframe_model);
   void OnScrollOffsetAnimated(ElementListType list_type,
-                              const gfx::ScrollOffset& scroll_offset);
+                              const gfx::ScrollOffset& scroll_offset,
+                              KeyframeModel* keyframe_model);
 
   static TargetProperties GetPropertiesMaskForAnimationState();
 
diff --git a/cc/animation/keyframe_model.cc b/cc/animation/keyframe_model.cc
index 10556098f..13b2f10 100644
--- a/cc/animation/keyframe_model.cc
+++ b/cc/animation/keyframe_model.cc
@@ -61,6 +61,7 @@
   DCHECK(!is_controlling_instance_);
   std::unique_ptr<KeyframeModel> to_return(
       new KeyframeModel(curve_->Clone(), id_, group_, target_property_id_));
+  to_return->element_id_ = element_id_;
   to_return->run_state_ = initial_run_state;
   to_return->iterations_ = iterations_;
   to_return->iteration_start_ = iteration_start_;
@@ -263,8 +264,7 @@
 }
 
 void KeyframeModel::PushPropertiesTo(KeyframeModel* other) const {
-  // Currently, we only push changes due to pausing and resuming KeyframeModels
-  // on the main thread.
+  other->element_id_ = element_id_;
   if (run_state_ == KeyframeModel::PAUSED ||
       other->run_state_ == KeyframeModel::PAUSED) {
     other->run_state_ = run_state_;
diff --git a/cc/animation/keyframe_model.h b/cc/animation/keyframe_model.h
index 329a9862..39557caa 100644
--- a/cc/animation/keyframe_model.h
+++ b/cc/animation/keyframe_model.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "base/time/time.h"
 #include "cc/animation/animation_export.h"
+#include "cc/trees/element_id.h"
 
 namespace cc {
 
@@ -69,6 +70,9 @@
   int group() const { return group_; }
   int target_property_id() const { return target_property_id_; }
 
+  ElementId element_id() const { return element_id_; }
+  void set_element_id(ElementId element_id) { element_id_ = element_id; }
+
   RunState run_state() const { return run_state_; }
   void SetRunState(RunState run_state, base::TimeTicks monotonic_time);
 
@@ -212,6 +216,10 @@
   // properties until all KeyframeModels in the group have finished animating.
   int group_;
 
+  // If specified, overrides the ElementId to apply this KeyframeModel's effect
+  // value on.
+  ElementId element_id_;
+
   int target_property_id_;
   RunState run_state_;
   double iterations_;
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc
index e6a8128..28bd021 100644
--- a/cc/trees/layer_tree_host.cc
+++ b/cc/trees/layer_tree_host.cc
@@ -1557,6 +1557,7 @@
                                     ElementListType list_type,
                                     Layer* layer) {
   element_layers_map_[element_id] = layer;
+  elements_in_property_trees_.insert(element_id);
   mutator_host_->RegisterElement(element_id, list_type);
 }
 
@@ -1564,6 +1565,27 @@
                                       ElementListType list_type) {
   mutator_host_->UnregisterElement(element_id, list_type);
   element_layers_map_.erase(element_id);
+  elements_in_property_trees_.erase(element_id);
+}
+
+void LayerTreeHost::SetActiveRegisteredElementIds(const ElementIdSet& ids) {
+  DCHECK(IsUsingLayerLists());
+
+  // Unregister ids that should no longer be registered.
+  for (auto id_iter = elements_in_property_trees_.begin();
+       id_iter != elements_in_property_trees_.end();) {
+    const auto& id = *(id_iter++);
+    if (!ids.count(id))
+      UnregisterElement(id, ElementListType::ACTIVE);
+  }
+
+  // Register new ids that were not already registered.
+  for (const auto& id : ids) {
+    if (!elements_in_property_trees_.count(id)) {
+      elements_in_property_trees_.insert(id);
+      mutator_host_->RegisterElement(id, ElementListType::ACTIVE);
+    }
+  }
 }
 
 static void SetElementIdForTesting(Layer* layer) {
@@ -1585,6 +1607,10 @@
 
 bool LayerTreeHost::IsElementInList(ElementId element_id,
                                     ElementListType list_type) const {
+  if (IsUsingLayerLists()) {
+    return list_type == ElementListType::ACTIVE &&
+           elements_in_property_trees_.count(element_id);
+  }
   return list_type == ElementListType::ACTIVE && LayerByElementId(element_id);
 }
 
diff --git a/cc/trees/layer_tree_host.h b/cc/trees/layer_tree_host.h
index c403263..b703304 100644
--- a/cc/trees/layer_tree_host.h
+++ b/cc/trees/layer_tree_host.h
@@ -500,6 +500,9 @@
 
   void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
   void PushLayerTreePropertiesTo(LayerTreeImpl* tree_impl);
+  // TODO(flackr): This list should be on the property trees and pushed
+  // as part of PushPropertyTreesTo.
+  void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl);
   void PushSurfaceRangesTo(LayerTreeImpl* tree_impl);
   void PushLayerTreeHostPropertiesTo(LayerTreeHostImpl* host_impl);
 
@@ -510,6 +513,17 @@
                        ElementListType list_type,
                        Layer* layer);
   void UnregisterElement(ElementId element_id, ElementListType list_type);
+
+  // Registers the new active element ids, updating |registered_element_ids_|,
+  // and unregisters any element ids that were previously registered. This is
+  // similar to |RegisterElement| and |UnregisterElement| but for layer lists
+  // where we do not have a unique element id to layer mapping.
+  using ElementIdSet = std::unordered_set<ElementId, ElementIdHash>;
+  void SetActiveRegisteredElementIds(const ElementIdSet&);
+  const ElementIdSet& elements_in_property_trees() {
+    return elements_in_property_trees_;
+  }
+
   void SetElementIdsForTesting();
 
   void BuildPropertyTreesForTesting();
@@ -782,6 +796,10 @@
 
   std::unordered_map<ElementId, Layer*, ElementIdHash> element_layers_map_;
 
+  // The set of registered element ids when using layer list mode. In non-layer-
+  // list mode, |element_layers_map_| is used.
+  ElementIdSet elements_in_property_trees_;
+
   bool in_paint_layer_contents_ = false;
 
   // This is true if atleast one layer in the layer tree has a copy request. We
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
index df595fa..413807c 100644
--- a/cc/trees/layer_tree_impl.cc
+++ b/cc/trees/layer_tree_impl.cc
@@ -614,7 +614,7 @@
 }
 
 bool LayerTreeImpl::IsElementInLayerList(ElementId element_id) const {
-  return elements_in_layer_list_.count(element_id);
+  return elements_in_property_trees_.count(element_id);
 }
 
 ElementListType LayerTreeImpl::GetElementTypeForAnimation() const {
@@ -623,9 +623,6 @@
 
 void LayerTreeImpl::AddToElementLayerList(ElementId element_id,
                                           LayerImpl* layer) {
-  DCHECK(layer);
-  DCHECK(layer->element_id() == element_id);
-
   if (!element_id)
     return;
 
@@ -635,17 +632,17 @@
 
 #if DCHECK_IS_ON()
   bool element_id_collision_detected =
-      elements_in_layer_list_.count(element_id);
+      elements_in_property_trees_.count(element_id);
 
   DCHECK(!element_id_collision_detected);
 #endif
 
-  elements_in_layer_list_.insert(element_id);
+  elements_in_property_trees_.insert(element_id);
 
   host_impl_->mutator_host()->RegisterElement(element_id,
                                               GetElementTypeForAnimation());
 
-  if (layer->scrollable())
+  if (layer && layer->scrollable())
     AddScrollableLayer(layer);
 }
 
@@ -660,7 +657,7 @@
   host_impl_->mutator_host()->UnregisterElement(element_id,
                                                 GetElementTypeForAnimation());
 
-  elements_in_layer_list_.erase(element_id);
+  elements_in_property_trees_.erase(element_id);
   element_id_to_scrollable_layer_.erase(element_id);
 }
 
diff --git a/cc/trees/layer_tree_impl.h b/cc/trees/layer_tree_impl.h
index 4221e20..43544fc 100644
--- a/cc/trees/layer_tree_impl.h
+++ b/cc/trees/layer_tree_impl.h
@@ -181,6 +181,7 @@
   void PushPropertyTreesTo(LayerTreeImpl* tree_impl);
   void PushPropertiesTo(LayerTreeImpl* tree_impl);
   void PushSurfaceRangesTo(LayerTreeImpl* tree_impl);
+  void PushRegisteredElementIdsTo(LayerTreeImpl* tree_impl);
 
   void MoveChangeTrackingToLayers();
 
@@ -607,6 +608,11 @@
 
   LayerTreeLifecycle& lifecycle() { return lifecycle_; }
 
+  const std::unordered_set<ElementId, ElementIdHash>&
+  elements_in_property_trees() {
+    return elements_in_property_trees_;
+  }
+
  protected:
   float ClampPageScaleFactorToLimits(float page_scale_factor) const;
   void PushPageScaleFactorAndLimits(const float* page_scale_factor,
@@ -619,6 +625,8 @@
   bool ClampBrowserControlsShownRatio();
 
  private:
+  friend class LayerTreeHost;
+
   TransformNode* PageScaleTransformNode();
   void UpdatePageScaleNode();
 
@@ -672,7 +680,7 @@
   base::flat_set<LayerImpl*> layers_that_should_push_properties_;
 
   // Set of ElementIds which are present in the |layer_list_|.
-  std::unordered_set<ElementId, ElementIdHash> elements_in_layer_list_;
+  std::unordered_set<ElementId, ElementIdHash> elements_in_property_trees_;
 
   std::unordered_map<ElementId, float, ElementIdHash>
       element_id_to_opacity_animations_;
diff --git a/cc/trees/tree_synchronizer.cc b/cc/trees/tree_synchronizer.cc
index c4b44c9..c31289f 100644
--- a/cc/trees/tree_synchronizer.cc
+++ b/cc/trees/tree_synchronizer.cc
@@ -87,6 +87,25 @@
 }
 
 template <typename LayerTreeType>
+void PushElementsInPropertyTreesTo(LayerTreeType* host,
+                                   LayerTreeImpl* tree_impl) {
+  for (auto id_iter = tree_impl->elements_in_property_trees().begin();
+       id_iter != tree_impl->elements_in_property_trees().end();) {
+    const auto& id = *(id_iter++);
+    if (!host->elements_in_property_trees().count(id))
+      tree_impl->RemoveFromElementLayerList(id);
+  }
+
+  for (const auto& id : host->elements_in_property_trees()) {
+    if (!tree_impl->IsElementInLayerList(id)) {
+      // TODO(flackr): We should expose adding element ids without a
+      // layer pointer.
+      tree_impl->AddToElementLayerList(id, nullptr);
+    }
+  }
+}
+
+template <typename LayerTreeType>
 void SynchronizeTreesInternal(LayerTreeType* source_tree,
                               LayerTreeImpl* tree_impl,
                               PropertyTrees* property_trees) {
@@ -154,6 +173,8 @@
   PushLayerPropertiesInternal(layers.begin(), layers.end(), active_tree);
   PushLayerPropertiesInternal(picture_layers.begin(), picture_layers.end(),
                               active_tree);
+  if (pending_tree->settings().use_layer_lists)
+    PushElementsInPropertyTreesTo(pending_tree, active_tree);
   pending_tree->ClearLayersThatShouldPushProperties();
 }
 
@@ -163,6 +184,10 @@
   TRACE_EVENT1("cc", "TreeSynchronizer::PushLayerPropertiesTo.Main",
                "layer_count", layers.size());
   PushLayerPropertiesInternal(layers.begin(), layers.end(), impl_tree);
+  // When using layer lists, we may not have layers for all property tree
+  // node ids and need to synchronize the registered id list.
+  if (host_tree->IsUsingLayerLists())
+    PushElementsInPropertyTreesTo(host_tree, impl_tree);
   host_tree->ClearLayersThatShouldPushProperties();
 }
 
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
index 7bd6b7bc..43e1712 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-gen-property-trees
@@ -142,6 +142,13 @@
 Bug(none) virtual/prefer_compositing_to_lcd_text/compositing/overflow/scaled-overflow.html [ Failure ]
 Bug(none) compositing/overflow/scaled-overflow.html [ Failure ]
 
+# Opacity not applied to descendant of animated filter node.
+crbug.com/905859 transitions/opacity-transform-transitions-inside-iframe.html [ Failure ]
+crbug.com/905859 virtual/threaded/transitions/opacity-transform-transitions-inside-iframe.html [ Failure ]
+
+# Antialiasing differences
+crbug.com/905861 virtual/threaded/animations/skew-notsequential-compositor.html [ Failure ]
+
 # Incorrect scrollbar invalidation.
 crbug.com/887000 virtual/prefer_compositing_to_lcd_text/scrollbars/hidden-scrollbars-invisible.html [ Failure ]
 
@@ -153,6 +160,39 @@
 
 crbug.com/884239 virtual/threaded/animations/animationworklet/worklet-animation-local-time-undefined.html [ Failure ]
 
+# CSS clip with filter and opacity leads to a DCHECK
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-shown-node-count-preserved-when-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-event-listeners.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-statistics.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-orphan-nodes.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-show-all.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-search-by-id.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-containment-shown-node-count-preserved-when-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-expand-collapse.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-show-next.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-loader.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-expansion-preserved-when-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-show-next.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-expansion-preserved-when-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-weak-dominator.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-sorting-instances.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-sorting-fields.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-show-ranges.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-shown-node-count-preserved-when-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-retainers.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-containment-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-comparison-dom-groups-change.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-containment-show-next.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-containment-show-all.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-show-all.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-inspect-dom-wrapper.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-sorting.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/cpu-profiler-save-load.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-summary-search.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-location.js [ Crash ]
+crbug.com/906154 http/tests/devtools/profiler/heap-snapshot-containment-expansion-preserved-when-sorting.js [ Crash ]
+
 # These tests have failures that were introduced between enabling BGPT for the
 # first time and later disabling it. These are not real failures and can be
 # rebaselined.
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2 b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
index 199efae..75659dd 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-slimming-paint-v2
@@ -494,6 +494,10 @@
 Bug(none) transforms/transformed-caret.html [ Pass Failure ]
 Bug(none) paint/invalidation/scroll/scroll-in-transformed-layer.html [ Failure ]
 Bug(none) paint/invalidation/scroll/scroll-with-transformed-parent-layer.html [ Failure ]
+Bug(none) fast/overflow/overflow-text-hit-testing.html [ Failure ]
+Bug(none) compositing/reflections/nested-reflection-animated.html [ Failure ]
+Bug(none) compositing/transitions/scale-transition-no-start.html [ Failure ]
+Bug(none) virtual/threaded/animations/skew-notsequential-compositor.html [ Failure ]
 
 crbug.com/644358 fast/block/float/float-overhanging-grandparent-change-self-painting.html [ Crash ]
 
@@ -561,6 +565,9 @@
 crbug.com/589265 fast/clip/overflow-border-radius-composited-parent.html [ Failure ]
 crbug.com/589265 fast/clip/overflow-border-radius-composited.html [ Failure ]
 
+# Opacity not applied to descendant of animated filter node.
+crbug.com/905859 transitions/opacity-transform-transitions-inside-iframe.html [ Failure ]
+
 # Notes about rebaselined tests:
 #
 # Rebaselined for small pixel differences.
diff --git a/third_party/WebKit/LayoutTests/animations/composited-filter-animation-expected.html b/third_party/WebKit/LayoutTests/animations/composited-filter-animation-expected.html
new file mode 100644
index 0000000..70ad065
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/composited-filter-animation-expected.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    background: green;
+  }
+</style>
+<div id="test"></div>
+<p>Verify that composited filter animations are applied correctly. If the box
+is green the animation has applied correctly.</p>
diff --git a/third_party/WebKit/LayoutTests/animations/composited-filter-animation.html b/third_party/WebKit/LayoutTests/animations/composited-filter-animation.html
new file mode 100644
index 0000000..d17868e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/animations/composited-filter-animation.html
@@ -0,0 +1,41 @@
+<!doctype html>
+<style>
+  div {
+    width: 100px;
+    height: 100px;
+    background: green;
+    filter: saturate(0);
+  }
+
+  @keyframes filter {
+    0% { filter: saturate(0); }
+    0.001% { filter: saturate(1); }
+    100% { filter: saturate(1); }
+  }
+</style>
+<div id="test"></div>
+<p>Verify that composited filter animations are applied correctly. If the box
+is green the animation has applied correctly.</p>
+<script>
+if (window.testRunner)
+  testRunner.waitUntilDone();
+test.addEventListener('animationstart', () => {
+
+  // Now the animation has started, wait until the time when we should see full
+  // saturation.
+  let animationStart = document.timeline.currentTime;
+  let targetPercentage = 0.001 / 100;
+  let targetTime = animationStart + 300000 * targetPercentage;
+
+  function waitForTargetTime(ts) {
+    if (ts >= targetTime) {
+      if (window.testRunner)
+        testRunner.notifyDone();
+      return;
+    }
+    requestAnimationFrame(waitForTargetTime);
+  }
+  requestAnimationFrame(waitForTargetTime);
+});
+test.style.animation = 'filter 300s';
+</script>
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index d041710..ef9d262 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -883,7 +883,7 @@
   CompositorElementId expected_compositor_element_id =
       CompositorElementIdFromUniqueObjectId(
           ToLayoutBoxModelObject(object_composited)->UniqueId(),
-          CompositorElementIdNamespace::kPrimary);
+          CompositorElementIdNamespace::kPrimaryEffect);
   composited_element_ids->insert(expected_compositor_element_id);
 
   Timing timing;
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.cc b/third_party/blink/renderer/core/animation/compositor_animations.cc
index 8f49819..acb29a45 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations.cc
@@ -143,6 +143,34 @@
   return false;
 }
 
+CompositorElementIdNamespace CompositorElementNamespaceForProperty(
+    CSSPropertyID property) {
+  if (!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() &&
+      !RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    // Pre-BlinkGenPropertyTrees, all animations affect the primary
+    // ElementId namespace.
+    return CompositorElementIdNamespace::kPrimary;
+  }
+  switch (property) {
+    case CSSPropertyOpacity:
+      return CompositorElementIdNamespace::kPrimaryEffect;
+    case CSSPropertyRotate:
+    case CSSPropertyScale:
+    case CSSPropertyTranslate:
+    case CSSPropertyTransform:
+      return CompositorElementIdNamespace::kPrimaryTransform;
+    case CSSPropertyFilter:
+    case CSSPropertyBackdropFilter: {
+      return CompositorElementIdNamespace::kEffectFilter;
+      case CSSPropertyVariable:
+        return CompositorElementIdNamespace::kPrimary;
+      default:
+        NOTREACHED();
+    }
+      return CompositorElementIdNamespace::kPrimary;
+  }
+}
+
 }  // namespace
 
 CompositorAnimations::FailureCode
@@ -204,8 +232,6 @@
             "Accelerated keyframe value could not be computed");
       }
 
-      CompositorElementIdNamespace property_namespace =
-          CompositorElementIdNamespace::kPrimary;
       // FIXME: Determine candidacy based on the CSSValue instead of a snapshot
       // AnimatableValue.
       switch (property.GetCSSProperty().PropertyID()) {
@@ -232,7 +258,6 @@
             return FailureCode::Actionable(
                 "Filter-related property may affect surrounding pixels");
           }
-          property_namespace = CompositorElementIdNamespace::kEffectFilter;
           break;
         }
         case CSSPropertyVariable: {
@@ -260,7 +285,8 @@
         CompositorElementId target_element_id =
             CompositorElementIdFromUniqueObjectId(
                 target_element.GetLayoutObject()->UniqueId(),
-                property_namespace);
+                CompositorElementNamespaceForProperty(
+                    property.GetCSSProperty().PropertyID()));
         DCHECK(target_element_id);
         if (!composited_element_ids->count(target_element_id)) {
           return FailureCode::NonActionable(
@@ -419,7 +445,7 @@
       ToKeyframeEffectModelBase(effect);
 
   Vector<std::unique_ptr<CompositorKeyframeModel>> keyframe_models;
-  GetAnimationOnCompositor(timing, group, start_time, time_offset,
+  GetAnimationOnCompositor(element, timing, group, start_time, time_offset,
                            keyframe_effect, keyframe_models,
                            animation_playback_rate);
   DCHECK(!keyframe_models.IsEmpty());
@@ -489,9 +515,20 @@
       return;
   }
 
+  CompositorElementIdNamespace element_id_namespace =
+      CompositorElementIdNamespace::kPrimary;
+  // With BlinkGenPropertyTrees we create an animation namespace element id
+  // when an element has created all property tree nodes which may be required
+  // by the keyframe effects. The animation affects multiple element ids, and
+  // one is pushed each KeyframeModel. See |GetAnimationOnCompositor|.
+  // Currently we use the kPrimaryEffect node to know if nodes have been
+  // created for animations.
+  if (RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
+      RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) {
+    element_id_namespace = CompositorElementIdNamespace::kPrimaryEffect;
+  }
   compositor_animation->AttachElement(CompositorElementIdFromUniqueObjectId(
-      element.GetLayoutObject()->UniqueId(),
-      CompositorElementIdNamespace::kPrimary));
+      element.GetLayoutObject()->UniqueId(), element_id_namespace));
 }
 
 bool CompositorAnimations::ConvertTimingForCompositor(
@@ -590,6 +627,7 @@
 }  // namespace
 
 void CompositorAnimations::GetAnimationOnCompositor(
+    const Element& target_element,
     const Timing& timing,
     int group,
     base::Optional<double> start_time,
@@ -678,6 +716,10 @@
     if (start_time)
       keyframe_model->SetStartTime(start_time.value());
 
+    keyframe_model->SetElementId(CompositorElementIdFromUniqueObjectId(
+        target_element.GetLayoutObject()->UniqueId(),
+        CompositorElementNamespaceForProperty(
+            property.GetCSSProperty().PropertyID())));
     keyframe_model->SetIterations(compositor_timing.adjusted_iteration_count);
     keyframe_model->SetIterationStart(compositor_timing.iteration_start);
     keyframe_model->SetTimeOffset(compositor_timing.scaled_time_offset);
diff --git a/third_party/blink/renderer/core/animation/compositor_animations.h b/third_party/blink/renderer/core/animation/compositor_animations.h
index 393ace9..30d53ab 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations.h
+++ b/third_party/blink/renderer/core/animation/compositor_animations.h
@@ -128,6 +128,7 @@
                                          double animation_playback_rate);
 
   static void GetAnimationOnCompositor(
+      const Element&,
       const Timing&,
       int group,
       base::Optional<double> start_time,
diff --git a/third_party/blink/renderer/core/animation/compositor_animations_test.cc b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
index 0f31c2a..5d4709a 100644
--- a/third_party/blink/renderer/core/animation/compositor_animations_test.cc
+++ b/third_party/blink/renderer/core/animation/compositor_animations_test.cc
@@ -124,7 +124,14 @@
 
     timeline_ = DocumentTimeline::Create(&GetDocument());
     timeline_->ResetForTesting();
-    element_ = GetDocument().CreateElementForBinding("test");
+
+    // Using will-change ensures that this object will need paint properties.
+    // Having an animation would normally ensure this but these tests don't
+    // explicitly construct a full animation on the element.
+    SetBodyInnerHTML(R"HTML(
+        <div id='test' style='will-change: opacity,filter,transform;'></div>
+    )HTML");
+    element_ = GetDocument().getElementById("test");
 
     helper_.Initialize(nullptr, nullptr, nullptr);
     base_url_ = "http://www.test.com/";
@@ -171,9 +178,9 @@
       StringKeyframeEffectModel& effect,
       Vector<std::unique_ptr<CompositorKeyframeModel>>& keyframe_models,
       double animation_playback_rate) {
-    CompositorAnimations::GetAnimationOnCompositor(timing, 0, base::nullopt, 0,
-                                                   effect, keyframe_models,
-                                                   animation_playback_rate);
+    CompositorAnimations::GetAnimationOnCompositor(
+        *element_, timing, 0, base::nullopt, 0, effect, keyframe_models,
+        animation_playback_rate);
   }
 
   bool DuplicateSingleKeyframeAndTestIsCandidateOnResult(
@@ -798,6 +805,7 @@
 
 TEST_F(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectOpacity) {
+  ScopedBlinkGenPropertyTreesForTest blink_gen_property_trees(true);
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
 
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
@@ -806,7 +814,7 @@
 
   CompositorElementIdSet compositor_ids;
   compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
-      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimary));
+      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimaryEffect));
 
   // We need an ID to be in the set, but not the same.
   CompositorElementId different_id = CompositorElementIdFromUniqueObjectId(
@@ -871,7 +879,8 @@
 
   // Timings have to be convertible for compositor.
   compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
-      new_layout_object->UniqueId(), CompositorElementIdNamespace::kPrimary));
+      new_layout_object->UniqueId(),
+      CompositorElementIdNamespace::kPrimaryEffect));
   EXPECT_TRUE(CheckCanStartEffectOnCompositor(
       timing, *element.Get(), animation, *animation_effect, compositor_ids));
   timing.end_delay = 1.0;
@@ -896,7 +905,7 @@
 
   CompositorElementIdSet compositor_ids;
   compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
-      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimary));
+      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimaryEffect));
 
   // Check that we notice the value is not animatable correctly.
   const CSSProperty& target_property1(GetCSSPropertyOutlineStyle());
@@ -1039,6 +1048,7 @@
 
 TEST_F(AnimationCompositorAnimationsTest,
        CanStartElementOnCompositorEffectTransform) {
+  ScopedBlinkGenPropertyTreesForTest blink_gen_property_trees(true);
   Persistent<Element> element = GetDocument().CreateElementForBinding("shared");
 
   LayoutObjectProxy* layout_object = LayoutObjectProxy::Create(element.Get());
@@ -1047,7 +1057,10 @@
 
   CompositorElementIdSet compositor_ids;
   compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
-      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimary));
+      layout_object->UniqueId(),
+      CompositorElementIdNamespace::kPrimaryTransform));
+  compositor_ids.insert(CompositorElementIdFromUniqueObjectId(
+      layout_object->UniqueId(), CompositorElementIdNamespace::kPrimaryEffect));
 
   CompositorElementId different_id = CompositorElementIdFromUniqueObjectId(
       layout_object->UniqueId(), CompositorElementIdNamespace::kEffectFilter);
diff --git a/third_party/blink/renderer/core/exported/web_layer_test.cc b/third_party/blink/renderer/core/exported/web_layer_test.cc
index 0dee0be..359904e 100644
--- a/third_party/blink/renderer/core/exported/web_layer_test.cc
+++ b/third_party/blink/renderer/core/exported/web_layer_test.cc
@@ -506,7 +506,7 @@
   DCHECK_EQ(outer_element_layer->element_id(),
             CompositorElementIdFromUniqueObjectId(
                 outer_element->GetLayoutObject()->UniqueId(),
-                CompositorElementIdNamespace::kEffectFilter));
+                CompositorElementIdNamespace::kPrimary));
   auto* inner_element = GetElementById("inner");
   auto* inner_element_layer = ContentLayerAt(ContentLayerCount() - 1);
   DCHECK_EQ(inner_element_layer->element_id(),
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
index 0464102..a937b20 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
@@ -589,8 +589,14 @@
   if (CompositingReasonFinder::RequiresCompositingForTransform(box))
     compositing_reasons |= CompositingReason::k3DTransform;
 
-  if (CompositingReasonFinder::RequiresCompositingForTransformAnimation(style))
-    compositing_reasons |= CompositingReason::kActiveTransformAnimation;
+  // Currently, we create transform nodes for an element whenever any property
+  // is being animated so that the existence of the effect node implies the
+  // existence of all nodes.
+  // TODO(flackr): Check for nodes for each KeyframeModel target
+  // property instead of creating all nodes and only create a transform node
+  // if needed, https://crbug.com/900241
+  compositing_reasons |=
+      CompositingReasonFinder::CompositingReasonsForAnimation(style);
 
   if (style.HasWillChangeCompositingHint() &&
       !style.SubtreeWillChangeContents())
@@ -682,7 +688,8 @@
                 ? TransformPaintPropertyNode::BackfaceVisibility::kHidden
                 : TransformPaintPropertyNode::BackfaceVisibility::kVisible;
         state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-            object_.UniqueId(), CompositorElementIdNamespace::kPrimary);
+            object_.UniqueId(),
+            CompositorElementIdNamespace::kPrimaryTransform);
       }
 
       OnUpdate(properties_->UpdateTransform(*context_.current.transform,
@@ -770,7 +777,13 @@
   if (style.Opacity() != 1.0f || style.HasWillChangeOpacityHint())
     return true;
 
-  if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
+  // Currently, we create effect nodes for an element whenever any property
+  // is being animated so that the existence of the effect node implies the
+  // existence of all nodes.
+  // TODO(flackr): Check for nodes for each KeyframeModel target
+  // property instead of creating all nodes and only create an effect node
+  // if needed, https://crbug.com/900241
+  if (CompositingReasonFinder::CompositingReasonsForAnimation(style))
     return true;
 
   if (object.StyleRef().HasMask())
@@ -884,13 +897,25 @@
         // We may begin to composite our subtree prior to an animation starts,
         // but a compositor element ID is only needed when an animation is
         // current.
-        if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
-                style)) {
-          state.direct_compositing_reasons =
-              CompositingReason::kActiveOpacityAnimation;
+        //
+        // Currently, we use the existence of this id to check if effect nodes
+        // have been created for animations on this element.
+        // TODO(flackr): Check for nodes for each KeyframeModel target
+        // property instead of creating all nodes and create each type of
+        // node as needed, https://crbug.com/900241
+        state.direct_compositing_reasons =
+            CompositingReasonFinder::CompositingReasonsForAnimation(style);
+        if (state.direct_compositing_reasons) {
+          state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+              object_.UniqueId(), CompositorElementIdNamespace::kPrimaryEffect);
+        } else {
+          // The effect node CompositorElementId is used to uniquely identify
+          // renderpasses so even if we don't need one for animations we still
+          // need to set an id. Using kPrimary avoids confusing cc::Animation
+          // into thinking the element has been composited for animations.
+          state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+              object_.UniqueId(), CompositorElementIdNamespace::kPrimary);
         }
-        state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
-            object_.UniqueId(), CompositorElementIdNamespace::kPrimary);
       }
       OnUpdate(properties_->UpdateEffect(*context_.current_effect,
                                          std::move(state)));
@@ -985,11 +1010,17 @@
 }
 
 static bool NeedsFilter(const LayoutObject& object) {
+  // Currently, we create filter nodes for an element whenever any property
+  // is being animated so that the existence of the effect node implies the
+  // existence of all animation nodes.
+  // TODO(flackr): Check for nodes for each KeyframeModel target
+  // property instead of creating all nodes and only create a filter node
+  // if needed, https://crbug.com/900241
   // TODO(trchen): SVG caches filters in SVGResources. Implement it.
   return (object.IsBoxModelObject() && ToLayoutBoxModelObject(object).Layer() &&
           (object.StyleRef().HasFilter() || object.HasReflection() ||
            object.HasBackdropFilter() ||
-           CompositingReasonFinder::RequiresCompositingForFilterAnimation(
+           CompositingReasonFinder::CompositingReasonsForAnimation(
                object.StyleRef())));
 }
 
@@ -1043,11 +1074,10 @@
         // We may begin to composite our subtree prior to an animation starts,
         // but a compositor element ID is only needed when an animation is
         // current.
+        // TODO(flackr): Only set a compositing reason for filter animation
+        // once we no longer need to create all nodes, https://crbug.com/900241
         state.direct_compositing_reasons =
-            CompositingReasonFinder::RequiresCompositingForFilterAnimation(
-                style)
-                ? CompositingReason::kActiveFilterAnimation
-                : CompositingReason::kNone;
+            CompositingReasonFinder::CompositingReasonsForAnimation(style);
         DCHECK(!style.HasCurrentFilterAnimation() ||
                state.direct_compositing_reasons != CompositingReason::kNone);
 
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
index 3f3d2d0..69b19f5 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder_test.cc
@@ -704,9 +704,12 @@
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
-       OpacityAnimationDoesNotCreateTransformNode) {
+       OpacityAnimationCreatesTransformAndFilterNodes) {
   LoadTestData("opacity-animation.html");
-  EXPECT_EQ(nullptr, PaintPropertiesForElement("target")->Transform());
+  // TODO(flackr): Verify that after https://crbug.com/900241 is fixed we no
+  // longer create transform or filter nodes for opacity animations.
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Transform());
+  EXPECT_NE(nullptr, PaintPropertiesForElement("target")->Filter());
 }
 
 TEST_P(PaintPropertyTreeBuilderTest,
@@ -4853,6 +4856,9 @@
   SetBodyInnerHTML("<div id='target' style='opacity: 0.5'></div");
   const ObjectPaintProperties* properties = PaintPropertiesForElement("target");
   EXPECT_TRUE(properties->Effect());
+  // TODO(flackr): Revisit whether effect ElementId should still exist when
+  // animations are no longer keyed off of the existence it:
+  // https://crbug.com/900241
   EXPECT_NE(CompositorElementId(),
             properties->Effect()->GetCompositorElementId());
 }
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
index 6bca95b..9938a03 100644
--- a/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_update_tests.cc
@@ -1099,7 +1099,9 @@
     EXPECT_TRUE(transform->HasDirectCompositingReasons());
     EXPECT_TRUE(transform->RequiresCompositingForAnimation());
   }
-  EXPECT_FALSE(filter->HasDirectCompositingReasons());
+  // TODO(flackr): After https://crbug.com/900241 is fixed the filter effect
+  // should no longer have direct compositing reasons due to the animation.
+  EXPECT_TRUE(filter->HasDirectCompositingReasons());
 
   target->setAttribute(html_names::kStyleAttr,
                        "transform: translateX(11px); filter: opacity(40%)");
diff --git a/third_party/blink/renderer/platform/BUILD.gn b/third_party/blink/renderer/platform/BUILD.gn
index 25ec990..2ef0040 100644
--- a/third_party/blink/renderer/platform/BUILD.gn
+++ b/third_party/blink/renderer/platform/BUILD.gn
@@ -1745,7 +1745,6 @@
     "graphics/paint/paint_controller_test.h",
     "graphics/paint/paint_property_node_test.cc",
     "graphics/paint/paint_record_builder_test.cc",
-    "graphics/paint/property_tree_state_test.cc",
     "graphics/paint/raster_invalidator_test.cc",
     "graphics/paint_invalidation_reason_test.cc",
     "graphics/path_test.cc",
diff --git a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
index eece33c..4f8a235 100644
--- a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
+++ b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.cc
@@ -53,6 +53,10 @@
       keyframe_model_->target_property_id());
 }
 
+void CompositorKeyframeModel::SetElementId(CompositorElementId element_id) {
+  keyframe_model_->set_element_id(element_id);
+}
+
 double CompositorKeyframeModel::Iterations() const {
   return keyframe_model_->iterations();
 }
diff --git a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
index 86d4a5b..2e5480b 100644
--- a/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
+++ b/third_party/blink/renderer/platform/animation/compositor_keyframe_model.h
@@ -10,6 +10,7 @@
 #include "base/memory/ptr_util.h"
 #include "cc/animation/keyframe_model.h"
 #include "third_party/blink/renderer/platform/animation/compositor_target_property.h"
+#include "third_party/blink/renderer/platform/graphics/compositor_element_id.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/noncopyable.h"
 
@@ -47,6 +48,8 @@
 
   CompositorTargetProperty::Type TargetProperty() const;
 
+  void SetElementId(CompositorElementId element_id);
+
   // This is the number of times that the animation will play. If this
   // value is zero the animation will not play. If it is negative, then
   // the animation will loop indefinitely.
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
index b6b0c0c..5331d61 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.cc
@@ -31,6 +31,31 @@
 
 namespace blink {
 
+namespace {
+
+// Inserts the element ids of the given node and all of its ancestors into the
+// given |composited_element_ids| set. Returns once it finds an id which already
+// exists as this implies that all of those ancestor nodes have already been
+// inserted.
+template <typename NodeType>
+void InsertAncestorElementIds(const NodeType* node,
+                              CompositorElementIdSet& composited_element_ids) {
+  while (node) {
+    const CompositorElementId& element_id = node->GetCompositorElementId();
+    if (element_id) {
+      if (composited_element_ids.count(element_id)) {
+        // Once we reach a node already counted we can stop traversing the
+        // parent chain.
+        return;
+      }
+      composited_element_ids.insert(element_id);
+    }
+    node = node->Parent() ? node->Parent()->Unalias() : nullptr;
+  }
+}
+
+}  // namespace
+
 // cc property trees make use of a sequence number to identify when tree
 // topology changes. For now we naively increment the sequence number each time
 // we update the property trees. We should explore optimizing our management of
@@ -765,20 +790,7 @@
     scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
         paint_artifact, pending_layer, layer_offset, new_content_layer_clients,
         new_scroll_hit_test_layers);
-    // Get the compositor element id for the layer. Scrollable layers are only
-    // associated with scroll element ids which are set in
-    // ScrollHitTestLayerForPendingLayer.
-    CompositorElementId element_id =
-        layer->scrollable()
-            ? layer->element_id()
-            : property_state.GetCompositorElementId(composited_element_ids);
-    // TODO(wkorman): Cease setting element id on layer once
-    // animation subsystem no longer requires element id to layer
-    // map. http://crbug.com/709137
-    // TODO(pdr): Element ids will still need to be set on scroll layers.
-    layer->SetElementId(element_id);
-    if (element_id)
-      composited_element_ids.insert(element_id);
+
     layer->SetLayerTreeHost(root_layer_->layer_tree_host());
 
     int transform_id =
@@ -809,6 +821,11 @@
     // condition for this. Do we need to do the same here?
     layer->SetShouldCheckBackfaceVisibility(backface_hidden);
 
+    InsertAncestorElementIds(property_state.Effect(), composited_element_ids);
+    InsertAncestorElementIds(transform, composited_element_ids);
+    if (layer->scrollable())
+      composited_element_ids.insert(layer->element_id());
+
     // If the property tree state has changed between the layer and the root, we
     // need to inform the compositor so damage can be calculated.
     // Calling |PropertyTreeStateChanged| for every pending layer is
@@ -835,6 +852,9 @@
 
   root_layer_->SetChildLayerList(layer_list_builder.Finalize());
 
+  // Update the host's active registered element ids.
+  host->SetActiveRegisteredElementIds(composited_element_ids);
+
   // Mark the property trees as having been rebuilt.
   host->property_trees()->sequence_number = g_s_property_tree_sequence_number;
   host->property_trees()->needs_rebuild = false;
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
index 894595e..06f78cf 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor_test.cc
@@ -2294,6 +2294,41 @@
   EXPECT_TRUE(composited_element_ids.count(effect->GetCompositorElementId()));
 }
 
+// If we have both a transform and an opacity animation, they should both be
+// included in the composited element id set returned from
+// |PaintArtifactCompositor::Update(...)|.
+TEST_P(PaintArtifactCompositorTest, UniqueAnimationCompositedElementIds) {
+  TransformPaintPropertyNode::State transform_state;
+  transform_state.direct_compositing_reasons =
+      CompositingReason::kActiveTransformAnimation;
+  transform_state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+      31, CompositorElementIdNamespace::kPrimaryTransform);
+  auto transform =
+      TransformPaintPropertyNode::Create(t0(), std::move(transform_state));
+
+  EffectPaintPropertyNode::State effect_state;
+  effect_state.local_transform_space = transform;
+  effect_state.output_clip = &c0();
+  effect_state.opacity = 2.0 / 255.0;
+  effect_state.direct_compositing_reasons =
+      CompositingReason::kActiveOpacityAnimation;
+  effect_state.compositor_element_id = CompositorElementIdFromUniqueObjectId(
+      41, CompositorElementIdNamespace::kPrimaryEffect);
+  auto effect = EffectPaintPropertyNode::Create(e0(), std::move(effect_state));
+
+  TestPaintArtifact artifact;
+  artifact.Chunk(*transform, c0(), *effect)
+      .RectDrawing(FloatRect(0, 0, 100, 100), Color::kBlack);
+
+  CompositorElementIdSet composited_element_ids;
+  Update(artifact.Build(), composited_element_ids);
+
+  EXPECT_EQ(2u, composited_element_ids.size());
+  EXPECT_TRUE(
+      composited_element_ids.count(transform->GetCompositorElementId()));
+  EXPECT_TRUE(composited_element_ids.count(effect->GetCompositorElementId()));
+}
+
 TEST_P(PaintArtifactCompositorTest, SkipChunkWithOpacityZero) {
   UpdateWithArtifactWithOpacity(0, false, false);
   ASSERT_EQ(0u, ContentLayerCount());
@@ -2443,15 +2478,18 @@
 
     Update(artifact.Build());
     ASSERT_EQ(1u, ContentLayerCount());
-    ASSERT_TRUE(GetLayerTreeHost().LayerByElementId(element_id));
+    ASSERT_TRUE(GetLayerTreeHost().IsElementInList(
+        element_id, cc::ElementListType::ACTIVE));
   }
 
   {
     TestPaintArtifact artifact;
-    ASSERT_TRUE(GetLayerTreeHost().LayerByElementId(element_id));
+    ASSERT_TRUE(GetLayerTreeHost().IsElementInList(
+        element_id, cc::ElementListType::ACTIVE));
     Update(artifact.Build());
     ASSERT_EQ(0u, ContentLayerCount());
-    ASSERT_FALSE(GetLayerTreeHost().LayerByElementId(element_id));
+    ASSERT_FALSE(GetLayerTreeHost().IsElementInList(
+        element_id, cc::ElementListType::ACTIVE));
   }
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
index 2986ada..3678cee 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
+++ b/third_party/blink/renderer/platform/graphics/compositor_element_id.cc
@@ -32,6 +32,8 @@
   DCHECK(namespace_id == CompositorElementIdNamespace::kPrimary ||
          namespace_id == CompositorElementIdNamespace::kScroll ||
          namespace_id == CompositorElementIdNamespace::kStickyTranslation ||
+         namespace_id == CompositorElementIdNamespace::kPrimaryEffect ||
+         namespace_id == CompositorElementIdNamespace::kPrimaryTransform ||
          namespace_id == CompositorElementIdNamespace::kEffectFilter ||
          namespace_id == CompositorElementIdNamespace::kEffectMask ||
          namespace_id == CompositorElementIdNamespace::kEffectClipPath ||
diff --git a/third_party/blink/renderer/platform/graphics/compositor_element_id.h b/third_party/blink/renderer/platform/graphics/compositor_element_id.h
index 34ef6a39..eeaeed8 100644
--- a/third_party/blink/renderer/platform/graphics/compositor_element_id.h
+++ b/third_party/blink/renderer/platform/graphics/compositor_element_id.h
@@ -19,7 +19,8 @@
   kUniqueObjectId,
   kScroll,
   kStickyTranslation,
-  // The following are SPv2-only.
+  kPrimaryEffect,
+  kPrimaryTransform,
   kEffectFilter,
   kEffectMask,
   kEffectClipPath,
diff --git a/third_party/blink/renderer/platform/graphics/paint/property_tree_state.cc b/third_party/blink/renderer/platform/graphics/paint/property_tree_state.cc
index 77924ae..741fe87 100644
--- a/third_party/blink/renderer/platform/graphics/paint/property_tree_state.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/property_tree_state.cc
@@ -22,29 +22,6 @@
                            effect_ ? effect_->Unalias() : nullptr);
 }
 
-const CompositorElementId PropertyTreeState::GetCompositorElementId(
-    const CompositorElementIdSet& element_ids) const {
-  // The effect or transform nodes could have a compositor element id. The order
-  // doesn't matter as the element id should be the same on all that have a
-  // non-default CompositorElementId.
-  //
-  // Note that PropertyTreeState acts as a context that accumulates state as we
-  // traverse the tree building layers. This means that we could see a
-  // compositor element id 'A' for a parent layer in conjunction with a
-  // compositor element id 'B' for a child layer. To preserve uniqueness of
-  // element ids, then, we check for presence in the |element_ids| set (which
-  // represents element ids already previously attached to a layer). This is an
-  // interim step while we pursue broader rework of animation subsystem noted in
-  // http://crbug.com/709137.
-  if (Effect()->GetCompositorElementId() &&
-      !element_ids.count(Effect()->GetCompositorElementId()))
-    return Effect()->GetCompositorElementId();
-  if (Transform()->GetCompositorElementId() &&
-      !element_ids.count(Transform()->GetCompositorElementId()))
-    return Transform()->GetCompositorElementId();
-  return CompositorElementId();
-}
-
 String PropertyTreeState::ToString() const {
   return String::Format("t:%p c:%p e:%p", Transform(), Clip(), Effect());
 }
diff --git a/third_party/blink/renderer/platform/graphics/paint/property_tree_state.h b/third_party/blink/renderer/platform/graphics/paint/property_tree_state.h
index 2637cb3..4cb5d2b 100644
--- a/third_party/blink/renderer/platform/graphics/paint/property_tree_state.h
+++ b/third_party/blink/renderer/platform/graphics/paint/property_tree_state.h
@@ -38,12 +38,6 @@
 
   static const PropertyTreeState& Root();
 
-  // Returns the compositor element id, if any, for this property state. If
-  // neither the effect nor transform nodes have a compositor element id then a
-  // default instance is returned.
-  const CompositorElementId GetCompositorElementId(
-      const CompositorElementIdSet& element_ids) const;
-
   void ClearChangedToRoot() const {
     Transform()->ClearChangedToRoot();
     Clip()->ClearChangedToRoot();
diff --git a/third_party/blink/renderer/platform/graphics/paint/property_tree_state_test.cc b/third_party/blink/renderer/platform/graphics/paint/property_tree_state_test.cc
index 5202781..6fbb0f1 100644
--- a/third_party/blink/renderer/platform/graphics/paint/property_tree_state_test.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/property_tree_state_test.cc
@@ -10,81 +10,4 @@
 
 class PropertyTreeStateTest : public testing::Test {};
 
-static scoped_refptr<TransformPaintPropertyNode>
-CreateTransformWithCompositorElementId(
-    const CompositorElementId& compositor_element_id) {
-  TransformPaintPropertyNode::State state;
-  state.compositor_element_id = compositor_element_id;
-  return TransformPaintPropertyNode::Create(TransformPaintPropertyNode::Root(),
-                                            std::move(state));
-}
-
-static scoped_refptr<EffectPaintPropertyNode>
-CreateEffectWithCompositorElementId(
-    const CompositorElementId& compositor_element_id) {
-  EffectPaintPropertyNode::State state;
-  state.compositor_element_id = compositor_element_id;
-  return EffectPaintPropertyNode::Create(EffectPaintPropertyNode::Root(),
-                                         std::move(state));
-}
-
-TEST_F(PropertyTreeStateTest, CompositorElementIdNoElementIdOnAnyNode) {
-  EXPECT_EQ(CompositorElementId(),
-            PropertyTreeState::Root().GetCompositorElementId(
-                CompositorElementIdSet()));
-}
-
-TEST_F(PropertyTreeStateTest, CompositorElementIdWithElementIdOnTransformNode) {
-  CompositorElementId expected_compositor_element_id = CompositorElementId(2);
-  auto transform =
-      CreateTransformWithCompositorElementId(expected_compositor_element_id);
-  PropertyTreeState state(transform.get(), &ClipPaintPropertyNode::Root(),
-                          &EffectPaintPropertyNode::Root());
-  EXPECT_EQ(expected_compositor_element_id,
-            state.GetCompositorElementId(CompositorElementIdSet()));
-}
-
-TEST_F(PropertyTreeStateTest, CompositorElementIdWithElementIdOnEffectNode) {
-  CompositorElementId expected_compositor_element_id = CompositorElementId(2);
-  auto effect =
-      CreateEffectWithCompositorElementId(expected_compositor_element_id);
-  PropertyTreeState state(&TransformPaintPropertyNode::Root(),
-                          &ClipPaintPropertyNode::Root(), effect.get());
-  EXPECT_EQ(expected_compositor_element_id,
-            state.GetCompositorElementId(CompositorElementIdSet()));
-}
-
-TEST_F(PropertyTreeStateTest, CompositorElementIdWithElementIdOnMultipleNodes) {
-  CompositorElementId expected_compositor_element_id = CompositorElementId(2);
-  auto transform =
-      CreateTransformWithCompositorElementId(expected_compositor_element_id);
-  auto effect =
-      CreateEffectWithCompositorElementId(expected_compositor_element_id);
-  PropertyTreeState state(transform.get(), &ClipPaintPropertyNode::Root(),
-                          effect.get());
-  EXPECT_EQ(expected_compositor_element_id,
-            state.GetCompositorElementId(CompositorElementIdSet()));
-}
-
-TEST_F(PropertyTreeStateTest, CompositorElementIdWithDifferingElementIds) {
-  CompositorElementId first_compositor_element_id = CompositorElementId(2);
-  CompositorElementId second_compositor_element_id = CompositorElementId(3);
-  auto transform =
-      CreateTransformWithCompositorElementId(first_compositor_element_id);
-  auto effect =
-      CreateEffectWithCompositorElementId(second_compositor_element_id);
-  PropertyTreeState state(transform.get(), &ClipPaintPropertyNode::Root(),
-                          effect.get());
-
-  CompositorElementIdSet composited_element_ids;
-  composited_element_ids.insert(first_compositor_element_id);
-  EXPECT_EQ(second_compositor_element_id,
-            state.GetCompositorElementId(composited_element_ids));
-
-  composited_element_ids.clear();
-  composited_element_ids.insert(second_compositor_element_id);
-  EXPECT_EQ(first_compositor_element_id,
-            state.GetCompositorElementId(composited_element_ids));
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.cc b/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.cc
index 87daad3..fe89049 100644
--- a/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.cc
+++ b/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.cc
@@ -17,27 +17,4 @@
   return *root;
 }
 
-const CompositorElementId RefCountedPropertyTreeState::GetCompositorElementId(
-    const CompositorElementIdSet& element_ids) const {
-  // The effect or transform nodes could have a compositor element id. The order
-  // doesn't matter as the element id should be the same on all that have a
-  // non-default CompositorElementId.
-  //
-  // Note that RefCountedPropertyTreeState acts as a context that accumulates
-  // state as we traverse the tree building layers. This means that we could see
-  // a compositor element id 'A' for a parent layer in conjunction with a
-  // compositor element id 'B' for a child layer. To preserve uniqueness of
-  // element ids, then, we check for presence in the |element_ids| set (which
-  // represents element ids already previously attached to a layer). This is an
-  // interim step while we pursue broader rework of animation subsystem noted in
-  // http://crbug.com/709137.
-  if (Effect()->GetCompositorElementId() &&
-      !element_ids.count(Effect()->GetCompositorElementId()))
-    return Effect()->GetCompositorElementId();
-  if (Transform()->GetCompositorElementId() &&
-      !element_ids.count(Transform()->GetCompositorElementId()))
-    return Transform()->GetCompositorElementId();
-  return CompositorElementId();
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h b/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h
index cd9c747..35174a7 100644
--- a/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h
+++ b/third_party/blink/renderer/platform/graphics/paint/ref_counted_property_tree_state.h
@@ -50,12 +50,6 @@
     return PropertyTreeState(transform_.get(), clip_.get(), effect_.get());
   }
 
-  // Returns the compositor element id, if any, for this property state. If
-  // neither the effect nor transform nodes have a compositor element id then a
-  // default instance is returned.
-  const CompositorElementId GetCompositorElementId(
-      const CompositorElementIdSet& element_ids) const;
-
   void ClearChangedToRoot() const {
     Transform()->ClearChangedToRoot();
     Clip()->ClearChangedToRoot();