Don't composite SVG element animating unsupported property by the compositor

[email protected]

(cherry picked from commit b647ada1ad2f56a3655707d05f4b25647e858659)

Bug: 1136764
Change-Id: Id909f6ef11c914ca8ff4c468c669a60d0f04dd31
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2464015
Reviewed-by: Fredrik Söderquist <[email protected]>
Commit-Queue: Xianzhu Wang <[email protected]>
Cr-Original-Commit-Position: refs/heads/master@{#816207}
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2465215
Reviewed-by: Xianzhu Wang <[email protected]>
Cr-Commit-Position: refs/branch-heads/4280@{#317}
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
index 413309dd5..f6f79dfe 100644
--- a/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_reason_finder_test.cc
@@ -395,6 +395,15 @@
         0% { transform: rotate(-5deg); }
         100% { transform: rotate(5deg); }
       }
+      .animate-mixed {
+        width: 100px;
+        height: 100px;
+        animation: mixed 1s infinite;
+      }
+      @keyframes mixed {
+        0% { transform: rotate(-5deg); stroke-dashoffset: 0; }
+        100% { transform: rotate(5deg); stroke-dashoffset: 180; }
+      }
     </style>
     <svg id="svg" class="animate">
       <rect id="rect" class="animate"/>
@@ -402,6 +411,7 @@
         <animateMotion dur="10s" repeatCount="indefinite"
                        path="M0,0 L100,100 z"/>
       </rect>
+      <rect id="rect-mixed" class="animate-mixed"/>
       <svg id="embedded-svg" class="animate"/>
       <foreignObject id="foreign" class="animate"/>
       <foreignObject id="foreign-zoomed" class="animate"
@@ -423,6 +433,9 @@
                 *GetLayoutObjectByElementId("rect-smil")));
   EXPECT_EQ(CompositingReason::kNone,
             CompositingReasonFinder::DirectReasonsForPaintProperties(
+                *GetLayoutObjectByElementId("rect-mixed")));
+  EXPECT_EQ(CompositingReason::kNone,
+            CompositingReasonFinder::DirectReasonsForPaintProperties(
                 *GetLayoutObjectByElementId("embedded-svg")));
   EXPECT_EQ(CompositingReason::kActiveTransformAnimation,
             CompositingReasonFinder::DirectReasonsForPaintProperties(
diff --git a/third_party/blink/renderer/core/svg/svg_element.cc b/third_party/blink/renderer/core/svg/svg_element.cc
index a8c0217e..70344216 100644
--- a/third_party/blink/renderer/core/svg/svg_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_element.cc
@@ -267,13 +267,52 @@
   });
 }
 
-bool SVGElement::HasMainThreadAnimations() const {
-  if (!HasSVGRareData())
+// TODO(crbug.com/1134652): For now composited animation doesn't work for SVG
+// if the animation also has properties other than the supported ones. We should
+// remove this when we make SVG CSS animations work in the same way as other
+// elements.
+static PropertyHandleSet SupportedCompositedAnimationProperties() {
+  DEFINE_STATIC_LOCAL(PropertyHandleSet, supported_properties,
+                      ({PropertyHandle(GetCSSPropertyOpacity()),
+                        PropertyHandle(GetCSSPropertyTransform()),
+                        PropertyHandle(GetCSSPropertyRotate()),
+                        PropertyHandle(GetCSSPropertyScale()),
+                        PropertyHandle(GetCSSPropertyTranslate()),
+                        PropertyHandle(GetCSSPropertyFilter()),
+                        PropertyHandle(GetCSSPropertyBackdropFilter())}));
+  return supported_properties;
+}
+
+static bool HasMainThreadAnimationProperty(const AnimationEffect* effect) {
+  const KeyframeEffectModelBase* model = nullptr;
+  if (auto* keyframe_effect = DynamicTo<KeyframeEffect>(effect))
+    model = DynamicTo<KeyframeEffectModelBase>(keyframe_effect->Model());
+  else if (auto* inert_effect = DynamicTo<InertEffect>(effect))
+    model = DynamicTo<KeyframeEffectModelBase>(inert_effect->Model());
+  if (!model)
     return false;
-  if (!SvgRareData()->WebAnimatedAttributes().IsEmpty())
+  for (auto& property : model->Properties()) {
+    if (!SupportedCompositedAnimationProperties().Contains(property))
+      return true;
+  }
+  return false;
+}
+
+bool SVGElement::HasMainThreadAnimations() const {
+  if (HasSVGRareData() && !SvgRareData()->WebAnimatedAttributes().IsEmpty())
     return true;
   if (GetSMILAnimations() && GetSMILAnimations()->HasAnimations())
     return true;
+  if (auto* element_animations = GetElementAnimations()) {
+    for (auto& entry : element_animations->Animations()) {
+      if (HasMainThreadAnimationProperty(entry.key->effect()))
+        return true;
+    }
+    for (auto& entry : element_animations->GetWorkletAnimations()) {
+      if (HasMainThreadAnimationProperty(entry->GetEffect()))
+        return true;
+    }
+  }
   return false;
 }