[CompositeClipPathAnimation] Add mock for paint definition test

Previously, unittests for composited clip path animations couldn't run the full document lifecycle because the lack of the clip path paint image generator would cause a crash. This CL allows for mocking of the generator, preserving all normal behavior except for binding to an actual paint worklet. This allows for main thread behaviors of composited cc animations to be tested.

Bug: 40503852

Change-Id: I0881072f35739977540dee393ad7d1dc7ddb62e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5276967
Reviewed-by: Olga Gerchikov <gerchiko@microsoft.com>
Commit-Queue: Claire Chambers <clchambers@microsoft.com>
Reviewed-by: Robert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1261953}
diff --git a/third_party/blink/renderer/core/frame/local_frame.cc b/third_party/blink/renderer/core/frame/local_frame.cc
index e842647..3be67cf 100644
--- a/third_party/blink/renderer/core/frame/local_frame.cc
+++ b/third_party/blink/renderer/core/frame/local_frame.cc
@@ -793,6 +793,12 @@
   return local_root.clip_path_paint_image_generator_.Get();
 }
 
+void LocalFrame::SetClipPathPaintImageGeneratorForTesting(
+    ClipPathPaintImageGenerator* generator) {
+  LocalFrame& local_root = LocalFrameRoot();
+  local_root.clip_path_paint_image_generator_ = generator;
+}
+
 LCPCriticalPathPredictor* LocalFrame::GetLCPP() {
   if (!LcppEnabled()) {
     return nullptr;
diff --git a/third_party/blink/renderer/core/frame/local_frame.h b/third_party/blink/renderer/core/frame/local_frame.h
index c21cea4..b693e611 100644
--- a/third_party/blink/renderer/core/frame/local_frame.h
+++ b/third_party/blink/renderer/core/frame/local_frame.h
@@ -307,6 +307,7 @@
   BackgroundColorPaintImageGenerator* GetBackgroundColorPaintImageGenerator();
   BoxShadowPaintImageGenerator* GetBoxShadowPaintImageGenerator();
   ClipPathPaintImageGenerator* GetClipPathPaintImageGenerator();
+  void SetClipPathPaintImageGeneratorForTesting(ClipPathPaintImageGenerator*);
   LCPCriticalPathPredictor* GetLCPP();
 
   // A local root is the root of a connected subtree that contains only
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
index 853e0d44..8a67c7fb 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.cc
@@ -257,6 +257,7 @@
 
 // TODO(crbug.com/1248605): Introduce helper functions commonly used by
 // background-color and clip-path animations.
+// static
 Animation* ClipPathPaintDefinition::GetAnimationIfCompositable(
     const Element* element) {
   return GetAnimationForProperty(element, GetCSSPropertyClipPath(),
@@ -312,14 +313,26 @@
   return paint_recorder.finishRecordingAsPicture();
 }
 
-// Creates a deferred image of size clip_area_size that will be painted via
-// paint worklet. The clip paths will be scaled and translated according to
-// reference_box.
+// TODO(crbug.com/325517328): Reorganize this to simplify or eliminate clip path
+// paint definition
 scoped_refptr<Image> ClipPathPaintDefinition::Paint(
     float zoom,
     const gfx::RectF& reference_box,
     const gfx::SizeF& clip_area_size,
     const Node& node) {
+  return Paint(zoom, reference_box, clip_area_size, node, worklet_id_);
+}
+
+// Creates a deferred image of size clip_area_size that will be painted via
+// paint worklet. The clip paths will be scaled and translated according to
+// reference_box.
+// static
+scoped_refptr<Image> ClipPathPaintDefinition::Paint(
+    float zoom,
+    const gfx::RectF& reference_box,
+    const gfx::SizeF& clip_area_size,
+    const Node& node,
+    int worklet_id) {
   DCHECK(node.IsElementNode());
   const Element* element = To<Element>(&node);
 
@@ -368,13 +381,14 @@
       CompositorPaintWorkletInput::NativePropertyType::kClipPath, element_id);
   scoped_refptr<ClipPathPaintWorkletInput> input =
       base::MakeRefCounted<ClipPathPaintWorkletInput>(
-          reference_box, clip_area_size, worklet_id_, zoom, animated_shapes,
+          reference_box, clip_area_size, worklet_id, zoom, animated_shapes,
           offsets, std::move(timing_functions), progress,
           std::move(input_property_keys));
 
   return PaintWorkletDeferredImage::Create(std::move(input), clip_area_size);
 }
 
+// static
 gfx::RectF ClipPathPaintDefinition::ClipAreaRect(
     const Node& node,
     const gfx::RectF& reference_box,
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
index 2d105bf..aeca6c0 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition.h
@@ -39,6 +39,13 @@
                              const gfx::RectF& reference_box,
                              const gfx::SizeF& clip_area_size,
                              const Node&);
+  // static method that accepts a worklet id, for use in tests. The instance
+  // version of this method calls this
+  static scoped_refptr<Image> Paint(float zoom,
+                                    const gfx::RectF& reference_box,
+                                    const gfx::SizeF& clip_area_size,
+                                    const Node&,
+                                    int worklet_id);
   // The bounding rect for the entire animation, fitting the clip path at its
   // largest extent
   static gfx::RectF ClipAreaRect(const Node& node,
diff --git a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
index 02c0bda..af939de 100644
--- a/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
+++ b/third_party/blink/renderer/modules/csspaint/nativepaint/clip_path_paint_definition_test.cc
@@ -10,16 +10,51 @@
 #include "third_party/blink/renderer/core/animation/keyframe_effect.h"
 #include "third_party/blink/renderer/core/animation/string_keyframe.h"
 #include "third_party/blink/renderer/core/animation/timing.h"
+#include "third_party/blink/renderer/core/css/clip_path_paint_image_generator.h"
 #include "third_party/blink/renderer/core/dom/element.h"
 #include "third_party/blink/renderer/core/execution_context/security_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/testing/page_test_base.h"
+#include "third_party/blink/renderer/platform/graphics/image.h"
 
 namespace blink {
 
+using CompositedPaintStatus = ElementAnimations::CompositedPaintStatus;
+
+class MockClipPathPaintImageGenerator : public ClipPathPaintImageGenerator {
+ public:
+  scoped_refptr<Image> Paint(float zoom,
+                             const gfx::RectF& reference_box,
+                             const gfx::SizeF& clip_area_size,
+                             const Node& node) override {
+    return ClipPathPaintDefinition::Paint(zoom, reference_box, clip_area_size,
+                                          node, 0 /* use a dummy worklet id */);
+  }
+  gfx::RectF ClipAreaRect(const Node& node,
+                          const gfx::RectF& reference_box,
+                          float zoom) const override {
+    return ClipPathPaintDefinition::ClipAreaRect(node, reference_box, zoom);
+  }
+  Animation* GetAnimationIfCompositable(const Element* element) override {
+    return ClipPathPaintDefinition::GetAnimationIfCompositable(element);
+  }
+  void Shutdown() override {}
+};
+
 class ClipPathPaintDefinitionTest : public PageTestBase {
  public:
   ClipPathPaintDefinitionTest() = default;
   ~ClipPathPaintDefinitionTest() override = default;
+
+ protected:
+  void SetUp() override {
+    PageTestBase::SetUp();
+    MockClipPathPaintImageGenerator* generator =
+        MakeGarbageCollected<MockClipPathPaintImageGenerator>();
+    GetFrame().SetClipPathPaintImageGeneratorForTesting(generator);
+    GetDocument().GetSettings()->SetAcceleratedCompositingEnabled(true);
+  }
 };
 
 // Test the case where there is a background-color animation with two simple
@@ -54,16 +89,23 @@
   model->SetComposite(EffectModel::kCompositeReplace);
 
   Element* element = GetElementById("target");
+  LayoutObject* lo = element->GetLayoutObject();
   NonThrowableExceptionState exception_state;
   DocumentTimeline* timeline =
       MakeGarbageCollected<DocumentTimeline>(&GetDocument());
   Animation* animation = Animation::Create(
       MakeGarbageCollected<KeyframeEffect>(element, model, timing), timeline,
       exception_state);
-  UpdateAllLifecyclePhasesForTest();
   animation->play();
 
+  UpdateAllLifecyclePhasesForTest();
+
+  // Ensure that the paint property was set correctly - composited animation
+  // uses a mask based clip.
+  EXPECT_TRUE(lo->FirstFragment().PaintProperties()->ClipPathMask());
   EXPECT_TRUE(element->GetElementAnimations());
+  EXPECT_EQ(element->GetElementAnimations()->CompositedClipPathStatus(),
+            CompositedPaintStatus::kComposited);
   EXPECT_EQ(element->GetElementAnimations()->Animations().size(), 1u);
   EXPECT_EQ(ClipPathPaintDefinition::GetAnimationIfCompositable(element),
             animation);