Bug 1439485 - Don't try to unthrottle transform animations that don't affect overflow region. r? draft
authorHiroyuki Ikezoe <hikezoe@mozilla.com>
Tue, 27 Feb 2018 14:46:32 +0900
changeset 760247 5500197c349c8fb59787e887c6d343f0046a0901
parent 760185 580d833df9c44acec686a9fb88b5f27e9d29f68d
push id100585
push userbmo:hikezoe@mozilla.com
push dateTue, 27 Feb 2018 05:47:18 +0000
bugs1439485
milestone60.0a1
Bug 1439485 - Don't try to unthrottle transform animations that don't affect overflow region. r? MozReview-Commit-ID: AtQPiPnsC3z
dom/animation/KeyframeEffectReadOnly.cpp
dom/animation/KeyframeEffectReadOnly.h
dom/animation/test/mozilla/file_restyles.html
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -765,22 +765,21 @@ KeyframeEffectReadOnly::ComposeStyle(
                "out of array bounds");
 
     ComposeStyleRule(Forward<ComposeAnimationResult>(aComposeResult),
                      prop,
                      *segment,
                      computedTiming);
   }
 
-  // If the animation produces any transform change hint, we need to record the
-  // current time to unthrottle the animation periodically when the animation is
-  // being throttled because it's scrolled out of view.
-  if (mCumulativeChangeHint & (nsChangeHint_UpdatePostTransformOverflow |
-                               nsChangeHint_AddOrRemoveTransform |
-                               nsChangeHint_UpdateTransformLayer)) {
+  // If the animation produces a transform change hint that affects the overflow
+  // region, we need to record the current time to unthrottle the animation
+  // periodically when the animation is being throttled because it's scrolled
+  // out of view.
+  if (HasTransformThatMightAffectOverflow()) {
     nsPresContext* presContext =
       nsContentUtils::GetContextForContent(mTarget->mElement);
     if (presContext) {
       TimeStamp now = presContext->RefreshDriver()->MostRecentRefresh();
       EffectSet* effectSet =
         EffectSet::GetEffectSet(mTarget->mElement, mTarget->mPseudoType);
       MOZ_ASSERT(effectSet, "ComposeStyle should only be called on an effect "
                             "that is part of an effect set");
@@ -1468,19 +1467,17 @@ KeyframeEffectReadOnly::CanThrottle() co
     }
 
     const bool isVisibilityHidden =
       !frame->IsVisibleOrMayHaveVisibleDescendants();
     if (isVisibilityHidden ||
         frame->IsScrolledOutOfView()) {
       // If there are transform change hints, unthrottle the animation
       // periodically since it might affect the overflow region.
-      if (mCumulativeChangeHint & (nsChangeHint_UpdatePostTransformOverflow |
-                                   nsChangeHint_AddOrRemoveTransform |
-                                   nsChangeHint_UpdateTransformLayer)) {
+      if (HasTransformThatMightAffectOverflow()) {
         return isVisibilityHidden
           ? CanThrottleTransformChangesInScrollable(*frame)
           : CanThrottleTransformChanges(*frame);
       }
       return true;
     }
   }
 
@@ -1509,17 +1506,17 @@ KeyframeEffectReadOnly::CanThrottle() co
     if (!layer ||
         effectSet->GetAnimationGeneration() !=
           layer->GetAnimationGeneration()) {
       return false;
     }
 
     // If this is a transform animation that affects the overflow region,
     // we should unthrottle the animation periodically.
-    if (record.mProperty == eCSSProperty_transform &&
+    if (HasTransformThatMightAffectOverflow() &&
         !CanThrottleTransformChangesInScrollable(*frame)) {
       return false;
     }
   }
 
   for (const AnimationProperty& property : mProperties) {
     if (!property.mIsRunningOnCompositor) {
       return false;
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -483,16 +483,27 @@ private:
     const nsIFrame* aFrame,
     AnimationPerformanceWarning::Type& aPerformanceWarning);
   static bool IsGeometricProperty(const nsCSSPropertyID aProperty);
 
   static const TimeDuration OverflowRegionRefreshInterval();
 
   void UpdateEffectSet(mozilla::EffectSet* aEffectSet = nullptr) const;
 
+  // Returns true if this effect has transform and the transform might affect
+  // the overflow region.
+  // This function is used for updating scroll bars or notifying intersection
+  // observers reflected by the transform.
+  bool HasTransformThatMightAffectOverflow() const
+  {
+    return mCumulativeChangeHint & (nsChangeHint_UpdatePostTransformOverflow |
+                                    nsChangeHint_AddOrRemoveTransform |
+                                    nsChangeHint_UpdateTransformLayer);
+  }
+
   // FIXME: This flag will be removed in bug 1324966.
   bool mIsComposingStyle = false;
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #endif // mozilla_dom_KeyframeEffectReadOnly_h
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -1591,12 +1591,37 @@ waitForAllPaints(() => {
       } else {
         todo_is(markers.length, 0,
                 'Bug 1307341 The opacity animation keeps running on the ' +
                 'compositor when color style is changed');
       }
       await ensureElementRemoval(div);
     }
   );
+
+  add_task(
+    async function no_overflow_transform_animations_in_scrollable_element() {
+      await SpecialPowers.pushPrefEnv({ set: [["ui.showHideScrollbars", 1]] });
+
+      var parentElement = addDiv(null,
+        { style: 'overflow-y: scroll; height: 100px;' });
+      var div = addDiv(null);
+      var animation =
+        div.animate({ transform: [ 'translateY(10px)', 'translateY(10px)' ] },
+                    100 * MS_PER_SEC);
+      parentElement.appendChild(div);
+
+      await animation.ready;
+      ok(SpecialPowers.wrap(animation).isRunningOnCompositor);
+
+      var markers = await observeStyling(20);
+      is(markers.length, 0,
+         'No-overflow transform animations running on the compositor should ' +
+         'never update style on the main thread');
+
+      await ensureElementRemoval(parentElement);
+    }
+  );
+
 });
 
 </script>
 </body>