Revert "[BGPT] Simplify and improve performance of transform decomposition"

This reverts commit 7181ee07e464941e2aa3889dd19c7c3ea5eebd8d.

Reason for revert: Caused problem of direct transform update. Some
transform decomposited for some layer contributing to the offset of
the layer can't be directly updated.

Original change's description:
> [BGPT] Simplify and improve performance of transform decomposition
> 
> Instead of decompositing transforms of pending layers before updating
> cc transforms, now decomposite a pending layer's transforms just after
> we create cc effect, clip and scroll nodes. We don't decomposite a
> transform if the cc transform node has been created during creating
> other cc property nodes.
> 
> Because decompositing transform of a layer is just to move the
> transform pointer up along the transform path, it won't affect other
> layers which may not decomposite the same transforms.
> 
> This improves performance by avoiding hash map accesses and additional
> pending layer iteration and blink paint property tree walks.
> 
> Change-Id: Idfdc6bc510cfb83a1b3eb3956cc2fb0a11d457a2
> Bug: 954520, 954493
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1597205
> Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
> Reviewed-by: Mason Freed <masonfreed@chromium.org>
> Reviewed-by: Philip Rogers <pdr@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#657459}

TBR=wangxianzhu@chromium.org,pdr@chromium.org,masonfreed@chromium.org

# Not skipping CQ checks because original CL landed > 1 day ago.

Bug: 954520, 954493, 966350
Change-Id: I300cdecc444c63ad5fb2c962289e7dcde480bbd7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1629231
Reviewed-by: Xianzhu Wang <wangxianzhu@chromium.org>
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Cr-Commit-Position: refs/heads/master@{#663354}
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 adeb47f..db269ac6 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
@@ -385,35 +385,10 @@
   rect_known_to_be_opaque = FloatRect();
 }
 
-// A pending layer can decomposite its transform node if:
-// 1. We have not created a cc::TransformNode for it during this update.
-// 2. It is not the root transform node.
-// 3. It is a 2d translation only.
-// 4. The transform is not used for scrolling - its ScrollNode() is nullptr.
-// 5. It has no direct compositing reasons, other than k3DTransform. Note
-//    that if it has a k3DTransform reason, check #3 above ensures that it
-//    isn't really 3D.
-// 6. It has FlattensInheritedTransform matching that of its direct parent.
-// 7. It has backface visibility matching its direct parent.
-static bool CanDecompositeTransform(const TransformPaintPropertyNode& node) {
-  // TODO(masonfreed): CAP is not yet implemented here.
-  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
-    return false;
-  return node.CcNodeId(g_s_property_tree_sequence_number) == -1 &&
-         !node.IsRoot() && node.IsIdentityOr2DTranslation() &&
-         !node.ScrollNode() && !node.IsAffectedByOuterViewportBoundsDelta() &&
-         !node.HasDirectCompositingReasonsOtherThan3dTransform() &&
-         node.FlattensInheritedTransformSameAsParent() &&
-         node.BackfaceVisibilitySameAsParent();
-}
-
-void PaintArtifactCompositor::PendingLayer::DecompositeTransforms() {
-  const auto* transform = &property_tree_state.Transform().Unalias();
-  while (CanDecompositeTransform(*transform)) {
-    offset_to_transform_parent += transform->Translation2D();
-    transform = SafeUnalias(transform->Parent());
-  }
-  property_tree_state.SetTransform(*transform);
+void PaintArtifactCompositor::PendingLayer::DecompositeTransform() {
+  const auto& transform = property_tree_state.Transform().Unalias();
+  property_tree_state.SetTransform(*transform.Parent());
+  offset_to_transform_parent += transform.Translation2D();
 }
 
 const PaintChunk& PaintArtifactCompositor::PendingLayer::FirstPaintChunk(
@@ -797,6 +772,95 @@
   }
 }
 
+// Walk the pending layer list and build up a table of transform nodes that
+// can be de-composited (replaced with offset_to_transform_parent). A
+// transform node can be de-composited if:
+//  1. It is not the root transform node.
+//  2. It is a 2d translation only.
+//  3. The transform is not used for scrolling - its ScrollNode() is nullptr.
+//  4. It has no direct compositing reasons, other than k3DTransform. Note
+//     that if it has a k3DTransform reason, check #2 above ensures that it
+//     isn't really 3D.
+//  5. It has FlattensInheritedTransform matching that of its direct parent.
+//  6. It has backface visibility matching its direct parent.
+//  7. No clips have local_transform_space referring to this transform node.
+//  8. No effects have local_transform_space referring to this transform node.
+//  9. All child transform nodes are also able to be de-composited.
+// This algorithm should be O(t+c+e) where t,c,e are the number of transform,
+// clip, and effect nodes in the full tree.
+void PaintArtifactCompositor::DecompositeTransforms() {
+  // TODO(masonfreed): CAP is not yet implemented here.
+  if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled())
+    return;
+  WTF::HashMap<const TransformPaintPropertyNode*, bool> can_be_decomposited;
+  WTF::HashSet<const void*> clips_and_effects_seen;
+  for (const auto& pending_layer : pending_layers_) {
+    const auto& property_state = pending_layer.property_tree_state;
+
+    // Lambda to handle marking a transform node false, and walking up all true
+    // parents and marking them false as well. This also handles inserting
+    // transform_node if it isn't in the map, and keeps track of clips or
+    // effects.
+    auto mark_not_decompositable =
+        [&can_be_decomposited](
+            const TransformPaintPropertyNode* transform_node) {
+          DCHECK(transform_node);
+          while (transform_node && !transform_node->IsRoot()) {
+            if (!can_be_decomposited.Contains(transform_node)) {
+              can_be_decomposited.insert(transform_node, false);
+            } else {
+              if (!can_be_decomposited.at(transform_node))
+                break;
+              can_be_decomposited.Set(transform_node, false);
+            }
+            transform_node = SafeUnalias(transform_node->Parent());
+          }
+        };
+
+    // Add the transform and all transform parents to the map.
+    for (const auto* node = &property_state.Transform().Unalias();
+         node && !can_be_decomposited.Contains(node);
+         node = SafeUnalias(node->Parent())) {
+      can_be_decomposited.insert(node, !node->IsRoot());
+      if (!node->IsIdentityOr2DTranslation() || node->ScrollNode() ||
+          node->IsAffectedByOuterViewportBoundsDelta() ||
+          node->HasDirectCompositingReasonsOtherThan3dTransform() ||
+          !node->FlattensInheritedTransformSameAsParent() ||
+          !node->BackfaceVisibilitySameAsParent()) {
+        mark_not_decompositable(node);
+      }
+    }
+
+    // Add clips and effects, and their parents, that we haven't already seen.
+    for (const auto* node = &property_state.Clip().Unalias();
+         node && !clips_and_effects_seen.Contains(node);
+         node = SafeUnalias(node->Parent())) {
+      clips_and_effects_seen.insert(node);
+      if (!node->IsRoot())
+        mark_not_decompositable(&node->LocalTransformSpace());
+    }
+    for (const auto* node = &property_state.Effect().Unalias();
+         node && !clips_and_effects_seen.Contains(node);
+         node = SafeUnalias(node->Parent())) {
+      clips_and_effects_seen.insert(node);
+      if (!node->IsRoot())
+        mark_not_decompositable(&node->LocalTransformSpace());
+    }
+  }
+
+  // Now, for any transform nodes that can be de-composited, re-map their
+  // transform to point to the correct parent, and set the
+  // offset_to_transform_parent.
+  for (auto& pending_layer : pending_layers_) {
+    const auto* transform_node = &pending_layer.property_tree_state.Transform();
+    while (transform_node && !transform_node->IsRoot() &&
+           can_be_decomposited.at(transform_node)) {
+      pending_layer.DecompositeTransform();
+      transform_node = SafeUnalias(transform_node->Parent());
+    }
+  }
+}
+
 void PaintArtifactCompositor::Update(
     scoped_refptr<const PaintArtifact> paint_artifact,
     const ViewportProperties& viewport_properties,
@@ -844,23 +908,45 @@
   for (auto& entry : synthesized_clip_cache_)
     entry.in_use = false;
 
+  // See if we can de-composite any transforms.
+  DecompositeTransforms();
+
   for (auto& pending_layer : pending_layers_) {
     const auto& property_state = pending_layer.property_tree_state;
+    const auto& transform = property_state.Transform();
     const auto& clip = property_state.Clip();
-    if (&clip.LocalTransformSpace() == &property_state.Transform()) {
+
+    if (&clip.LocalTransformSpace() == &transform) {
       // Limit layer bounds to hide the areas that will be never visible because
       // of the clip.
       pending_layer.bounds.Intersect(clip.ClipRect().Rect());
-    } else if (const auto* scroll = property_state.Transform().ScrollNode()) {
+    } else if (const auto* scroll = transform.ScrollNode()) {
       // Limit layer bounds to the scroll range to hide the areas that will
       // never be scrolled into the visible area.
       pending_layer.bounds.Intersect(FloatRect(
           IntRect(scroll->ContainerRect().Location(), scroll->ContentsSize())));
     }
 
+    scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
+        paint_artifact, pending_layer, new_content_layer_clients,
+        new_scroll_hit_test_layers);
+
+    // Pre-CompositeAfterPaint, touch action rects are updated through
+    // ScrollingCoordinator::UpdateLayerTouchActionRects.
+    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
+      auto paint_chunks = paint_artifact->GetPaintChunkSubset(
+          pending_layer.paint_chunk_indices);
+      UpdateTouchActionRects(layer.get(), layer->offset_to_transform_parent(),
+                             property_state, paint_chunks);
+    }
+
+    layer->SetLayerTreeHost(root_layer_->layer_tree_host());
+
+    int transform_id =
+        property_tree_manager.EnsureCompositorTransformNode(transform);
     int clip_id = property_tree_manager.EnsureCompositorClipNode(clip);
     int effect_id = property_tree_manager.SwitchToEffectNodeWithSynthesizedClip(
-        property_state.Effect(), clip);
+        property_state.Effect(), clip, layer->DrawsContent());
     blink_effects.resize(effect_id + 1);
     blink_effects[effect_id] = &property_state.Effect();
     // The compositor scroll node is not directly stored in the property tree
@@ -870,32 +956,6 @@
     int scroll_id =
         property_tree_manager.EnsureCompositorScrollNode(scroll_translation);
 
-    // Decomposite and update transform after updating all other property nodes
-    // have been updated, so that we don't decomposite the transform nodes that
-    // are referenced by the other property nodes of this layer.
-    // Note that this may change property_state.Transform().
-    pending_layer.DecompositeTransforms();
-    int transform_id = property_tree_manager.EnsureCompositorTransformNode(
-        property_state.Transform());
-
-    scoped_refptr<cc::Layer> layer = CompositedLayerForPendingLayer(
-        paint_artifact, pending_layer, new_content_layer_clients,
-        new_scroll_hit_test_layers);
-
-    if (layer->DrawsContent())
-      property_tree_manager.ClearPendingSyntheticMaskLayers();
-
-    layer->SetLayerTreeHost(root_layer_->layer_tree_host());
-
-    // In Pre-CompositeAfterPaint, touch action rects are updated through
-    // ScrollingCoordinator::UpdateLayerTouchActionRects.
-    if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled()) {
-      auto paint_chunks = paint_artifact->GetPaintChunkSubset(
-          pending_layer.paint_chunk_indices);
-      UpdateTouchActionRects(layer.get(), layer->offset_to_transform_parent(),
-                             property_state, paint_chunks);
-    }
-
     layer_list_builder.Add(layer);
 
     layer->set_property_tree_sequence_number(
diff --git a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
index 5a2c3fc..3e13c67 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/paint_artifact_compositor.h
@@ -213,7 +213,7 @@
     // to the chunks as Skia commands.
     void Upcast(const PropertyTreeState&);
 
-    void DecompositeTransforms();
+    void DecompositeTransform();
 
     const PaintChunk& FirstPaintChunk(const PaintArtifact&) const;
 
@@ -225,6 +225,8 @@
     bool requires_own_layer;
   };
 
+  void DecompositeTransforms();
+
   // Collects the PaintChunks into groups which will end up in the same
   // cc layer. This is the entry point of the layerization algorithm.
   void CollectPendingLayers(const PaintArtifact&, const Settings& settings);
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
index 317430a..562b3e5 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.cc
@@ -672,7 +672,8 @@
 
 int PropertyTreeManager::SwitchToEffectNodeWithSynthesizedClip(
     const EffectPaintPropertyNode& next_effect,
-    const ClipPaintPropertyNode& next_clip) {
+    const ClipPaintPropertyNode& next_clip,
+    bool layer_draws_content) {
   // This function is expected to be invoked right before emitting each layer.
   // It keeps track of the nesting of clip and effects, output a composited
   // effect node whenever an effect is entered, or a non-trivial clip is
@@ -728,6 +729,9 @@
   BuildEffectNodesRecursively(next_effect);
   SynthesizeCcEffectsForClipsIfNeeded(next_clip, SkBlendMode::kSrcOver);
 
+  if (layer_draws_content)
+    pending_synthetic_mask_layers_.clear();
+
   return current_.effect_id;
 }
 
diff --git a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
index a9811c2..ffbe436 100644
--- a/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
+++ b/third_party/blink/renderer/platform/graphics/compositing/property_tree_manager.h
@@ -110,12 +110,8 @@
   // effect, i.e. applying the clip as a mask.
   int SwitchToEffectNodeWithSynthesizedClip(
       const EffectPaintPropertyNode& next_effect,
-      const ClipPaintPropertyNode& next_clip);
-
-  void ClearPendingSyntheticMaskLayers() {
-    pending_synthetic_mask_layers_.clear();
-  }
-
+      const ClipPaintPropertyNode& next_clip,
+      bool layer_draws_content);
   // Expected to be invoked after emitting the last layer. This will exit all
   // effects on the effect stack, generating clip mask layers for all the
   // unclosed synthesized clips.