Bug 1430884 - Throttle nsChangeHint_UpdateContainingBlock on invisible element. r?birtles
When an animation targets a CSS property that could cause a containing block to
be generated for its descendants, this containing block must be generated even
if the particular property values used by the animation would not normally
trigger generation of a containing block (e.g. transform: none). This is due
to the implicit application of will-change defined in CSS Animations[1] and Web
Animations[2].
Since this containing block is generated at the start of the animations, we can
throttle animations that produce the UpdateContainingBlock change hint for
animations that are not visible since they shouldn't have any further side
effects beyond the generation of containing blocks (which have already happened).
[1] https://drafts.csswg.org/css-animations/#animations
[2] https://drafts.csswg.org/web-animations-1/#side-effects-section
Unfortunately perspective animations starting with 'none' and transform
animations from 'none' to 'none' don't create a containing block (
bug 1470349
and
bug 1470370). That doesn't block the optimization in this patch, however,
since those bugs occur regardless of element visibility.
MozReview-Commit-ID: 8rTl8dShHrD
--- a/dom/animation/test/mozilla/file_restyles.html
+++ b/dom/animation/test/mozilla/file_restyles.html
@@ -1751,12 +1751,34 @@ waitForAllPaints(() => {
const markers = await observeStyling(5);
is(markers.length, 0,
'Outline offset animation running on the main-thread on invisible ' +
'element should be throttled');
await ensureElementRemoval(div);
});
+ add_task(async function restyling_transform_aimations_on_invisible_element() {
+ if (isAndroid) {
+ // FIXME: Bug 1470798: Enable this test on Android.
+ return;
+ }
+ // 'opacity: 0' prevents transform animations to be sent to the compositor.
+ const div = addDiv(null, { style: 'visibility: hidden; opacity: 0' });
+
+ const animation =
+ div.animate({ transform: [ 'none', 'rotate(360deg)' ] },
+ { duration: 100 * MS_PER_SEC,
+ iterations: Infinity });
+
+ await waitForAnimationReadyToRestyle(animation);
+
+ const markers = await observeStyling(5);
+
+ is(markers.length, 0,
+ 'Transform animations on visibility hidden element should be throttled');
+ await ensureElementRemoval(div);
+ });
+
});
</script>
</body>
--- a/layout/base/nsChangeHint.h
+++ b/layout/base/nsChangeHint.h
@@ -456,16 +456,17 @@ static_assert(!(nsChangeHint_Hints_Alway
#define NS_STYLE_HINT_REFLOW \
nsChangeHint(NS_STYLE_HINT_VISUAL | nsChangeHint_AllReflowHints)
#define nsChangeHint_Hints_CanIgnoreIfNotVisible \
nsChangeHint(NS_STYLE_HINT_VISUAL | \
nsChangeHint_NeutralChange | \
nsChangeHint_UpdateOpacityLayer | \
nsChangeHint_AddOrRemoveTransform | \
+ nsChangeHint_UpdateContainingBlock | \
nsChangeHint_UpdateOverflow | \
nsChangeHint_UpdatePostTransformOverflow | \
nsChangeHint_UpdateTransformLayer | \
nsChangeHint_UpdateUsesOpacity | \
nsChangeHint_VisibilityChange)
// NB: Once we drop support for the old style system, this logic should be
// inlined in the Servo style system to eliminate the FFI call.