Bug 1073396 - Make Element.getAnimationPlayers flush style; r=dbaron
authorBrian Birtles <birtles@gmail.com>
Thu, 02 Oct 2014 15:14:13 +0900
changeset 231560 41476731392e5071854bd36eb52faa7a40e8fde7
parent 231559 79ea9a38b446e5e46b66fec7365d2ed5e50891a8
child 231561 723e749323c64d9aa7ee4ffeb51314da2b7e8d45
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdbaron
bugs1073396
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1073396 - Make Element.getAnimationPlayers flush style; r=dbaron
content/base/src/Element.cpp
dom/animation/test/chrome/test_running_on_compositor.html
dom/animation/test/css-integration/test_animation-effect-name.html
dom/animation/test/css-integration/test_animations-dynamic-changes.html
dom/animation/test/css-integration/test_element-get-animation-players.html
--- a/content/base/src/Element.cpp
+++ b/content/base/src/Element.cpp
@@ -2934,16 +2934,21 @@ void
 Element::MozRequestPointerLock()
 {
   OwnerDoc()->RequestPointerLock(this);
 }
 
 void
 Element::GetAnimationPlayers(nsTArray<nsRefPtr<AnimationPlayer> >& aPlayers)
 {
+  nsIDocument* doc = GetComposedDoc();
+  if (doc) {
+    doc->FlushPendingNotifications(Flush_Style);
+  }
+
   nsIAtom* properties[] = { nsGkAtoms::transitionsProperty,
                             nsGkAtoms::animationsProperty };
   for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties);
        propIdx++) {
     AnimationPlayerCollection* collection =
       static_cast<AnimationPlayerCollection*>(
         GetProperty(properties[propIdx]));
     if (!collection) {
--- a/dom/animation/test/chrome/test_running_on_compositor.html
+++ b/dom/animation/test/chrome/test_running_on_compositor.html
@@ -37,17 +37,16 @@ var div = document.querySelector('div.ta
 
 const OMTAPrefKey = 'layers.offmainthreadcomposition.async-animations';
 var omtaEnabled = SpecialPowers.DOMWindowUtils.layerManagerRemote &&
                   SpecialPowers.getBoolPref(OMTAPrefKey);
 
 // FIXME: When we implement Element.animate, use that here instead of CSS
 // so that we remove any dependency on the CSS mapping.
 div.style.animation = 'anim 100s';
-window.getComputedStyle(div).animationName;
 var player = div.getAnimationPlayers()[0];
 
 // Wait so that animation can be set up.
 // FIXME: When we implement the AnimationPlayer.ready promise we should wait
 // on that here.
 window.requestAnimationFrame(function() {
   is(player.isRunningOnCompositor, omtaEnabled,
      'AnimationPlayer reports that it is running on the compositor'
--- a/dom/animation/test/css-integration/test_animation-effect-name.html
+++ b/dom/animation/test/css-integration/test_animation-effect-name.html
@@ -15,51 +15,44 @@ function addDiv() {
   var div = document.createElement('div');
   document.body.appendChild(div);
   return div;
 }
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'xyz 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Animation effect name matches keyframes rule name');
   div.remove();
 }, 'Effect name makes keyframe rule');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'x\\yz 100s';
-  dump(window.getComputedStyle(div).animationName + "\n");
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Escaped animation effect name matches keyframes rule name');
   div.remove();
 }, 'Escaped animation name');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'x\\79 z 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, 'xyz',
                 'Hex-escaped animation effect name matches keyframes rule'
                 + ' name');
   div.remove();
 }, 'Animation name with hex-escape');
 
 test(function() {
   var div = addDiv();
 
   // Add a transition
   div.style.left = '0px';
   window.getComputedStyle(div).transitionProperty;
   div.style.transition = 'all 100s';
   div.style.left = '100px';
-  window.getComputedStyle(div).left;
 
   assert_equals(div.getAnimationPlayers()[0].source.effect.name, '',
                 'Animation effects for transitions have an empty name');
   div.remove();
 }, 'Effect name for transitions');
 </script>
--- a/dom/animation/test/css-integration/test_animations-dynamic-changes.html
+++ b/dom/animation/test/css-integration/test_animations-dynamic-changes.html
@@ -16,27 +16,25 @@ function addDiv() {
   var div = document.createElement('div');
   document.body.appendChild(div);
   return div;
 }
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   var originalPlayer = div.getAnimationPlayers()[0];
   var originalStartTime = originalPlayer.startTime;
   var originalCurrentTime = originalPlayer.currentTime;
 
   // Wait a moment so we can confirm the startTime doesn't change (and doesn't
   // simply reflect the current time).
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animationDuration = '200s';
-    window.getComputedStyle(div).animationDuration;
     var player = div.getAnimationPlayers()[0];
     assert_equals(player, originalPlayer,
                   'The same AnimationPlayer is returned after updating'
                   + ' animation duration');
     assert_equals(player.startTime, originalStartTime,
                   'AnimationPlayers returned by getAnimationPlayers preserve'
                   + ' their startTime even when they are updated');
     // Sanity check
@@ -46,49 +44,45 @@ async_test(function(t) {
     div.remove();
     t.done();
   }));
 }, 'AnimationPlayers preserve their startTime when changed');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   // Store original state
   var players = div.getAnimationPlayers();
   var player1 = players[0];
   var player2 = players[1];
 
   // Update first in list
   div.style.animationDuration = '200s, 100s';
-  window.getComputedStyle(div).animationDuration;
   players = div.getAnimationPlayers();
   assert_equals(players[0], player1,
                 'First player is in same position after update');
   assert_equals(players[1], player2,
                 'Second player is in same position after update');
 }, 'Updated AnimationPlayers maintain their order in the list');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 200s, anim1 100s';
-  window.getComputedStyle(div).animationName;
 
   // Store original state
   var players = div.getAnimationPlayers();
   var player1 = players[0];
   var player2 = players[1];
 
   // Wait before continuing so we can compare start times
   window.requestAnimationFrame(t.step_func(function() {
     // Swap duration of first and second in list and prepend animation at the
     // same time
     div.style.animation = 'anim1 100s, anim1 100s, anim1 200s';
-    window.getComputedStyle(div).animationName;
     players = div.getAnimationPlayers();
     assert_true(players[0] !== player1 && players[0] !== player2,
                 'New player is prepended to start of list');
     assert_equals(players[1], player1,
                   'First player is in second position after update');
     assert_equals(players[2], player2,
                   'Second player is in third position after update');
     assert_equals(players[1].startTime, players[2].startTime,
@@ -98,53 +92,47 @@ async_test(function(t) {
     div.remove();
     t.done();
   }));
 }, 'Only the startTimes of existing animations are preserved');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   var secondPlayer = div.getAnimationPlayers()[1];
 
   // Wait before continuing so we can compare start times
   window.requestAnimationFrame(t.step_func(function() {
     // Trim list of animations
     div.style.animationName = 'anim1';
-    window.getComputedStyle(div).animationName;
     var players = div.getAnimationPlayers();
     assert_equals(players.length, 1, 'List of players was trimmed');
     assert_equals(players[0], secondPlayer,
                   'Remaining player is the second one in the list');
     assert_true(players[0].startTime < players[0].timeline.currentTime,
                 'Remaining player preserves startTime');
     div.remove();
     t.done();
   }));
 }, 'Animations are removed from the start of the list while preserving'
    + ' the state of existing players');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
   var firstAddedPlayer = div.getAnimationPlayers()[0];
 
   // Wait and add second player
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animation = 'anim1 100s, anim1 100s';
-    window.getComputedStyle(div).animationName;
     var secondAddedPlayer = div.getAnimationPlayers()[0];
 
     // Wait again and add another player
     window.requestAnimationFrame(t.step_func(function() {
       div.style.animation = 'anim1 100s, anim2 100s, anim1 100s';
-      window.getComputedStyle(div).animationName;
       var players = div.getAnimationPlayers();
       assert_not_equals(firstAddedPlayer, secondAddedPlayer,
                         'New players are added to start of the list');
       assert_equals(players[0], secondAddedPlayer,
                     'Second player remains in same position after'
                     + ' interleaving');
       assert_equals(players[2], firstAddedPlayer,
                     'First player remains in same position after'
--- a/dom/animation/test/css-integration/test_element-get-animation-players.html
+++ b/dom/animation/test/css-integration/test_element-get-animation-players.html
@@ -32,31 +32,29 @@ test(function() {
   div.remove();
 }, 'getAnimationPlayers for non-animated content');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Add an animation
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns a player running CSS Animations');
   var startTime = players[0].startTime;
   assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
     'CSS animation has a sensible start time');
 
   // Wait a moment then add a second animation.
   //
   // We wait for the next frame so that we can test that the start times of
   // the animations differ.
   window.requestAnimationFrame(t.step_func(function() {
     div.style.animation = 'anim1 100s, anim2 100s';
-    window.getComputedStyle(div).animationName;
     players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers returns one player for each value of'
       + ' animation-name');
     assert_true(players[0].startTime < players[1].startTime,
       'Additional players for CSS animations start after the original'
       + ' animation and appear later in the list');
     div.remove();
@@ -64,48 +62,46 @@ async_test(function(t) {
   }));
 }, 'getAnimationPlayers for CSS Animations');
 
 test(function() {
   var div = addDiv();
 
   // Add an animation that targets multiple properties
   div.style.animation = 'multiPropAnim 100s';
-  window.getComputedStyle(div).animationName;
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns only one player for a CSS Animation'
     + ' that targets multiple properties');
   div.remove();
 }, 'getAnimationPlayers for multi-property animations');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Add a couple of transitions
   div.style.left = '0px';
   div.style.top = '0px';
   window.getComputedStyle(div).transitionProperty;
+
   div.style.transition = 'all 100s';
   div.style.left = '100px';
   div.style.top = '100px';
-  window.getComputedStyle(div).left;
 
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 2,
     'getAnimationPlayers() returns one player per transitioning property');
   var startTime = players[0].startTime;
   assert_true(startTime > 0 && startTime <= document.timeline.currentTime,
     'CSS transitions have sensible start times');
   assert_equals(players[0].startTime, players[1].startTime,
     'CSS transitions started together have the same start time');
 
   // Wait a moment then add a third transition
   window.requestAnimationFrame(t.step_func(function() {
     div.style.backgroundColor = 'green';
-    window.getComputedStyle(div).backgroundColor;
     players = div.getAnimationPlayers();
     assert_equals(players.length, 3,
       'getAnimationPlayers returns players for all running CSS Transitions');
     assert_true(players[1].startTime < players[2].startTime,
       'Player for additional CSS transition starts after the original'
       + ' transitions and appears later in the list');
     div.remove();
     t.done();
@@ -119,17 +115,16 @@ async_test(function(t) {
   div.style.backgroundColor = 'red';
   div.style.animation = 'anim1 100s';
   window.getComputedStyle(div).backgroundColor;
 
   // Wait a moment then add a transition
   window.requestAnimationFrame(t.step_func(function() {
     div.style.transition = 'all 100s';
     div.style.backgroundColor = 'green';
-    window.getComputedStyle(div).backgroundColor;
 
     var players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers returns players for both animations and '
       + ' transitions that run simultaneously');
     assert_true(players[0].startTime > players[1].startTime,
       'players for transitions appear before animations even if they '
       + ' start later');
@@ -147,205 +142,183 @@ async_test(function(t) {
       'getAnimationPlayers does not return players for finished '
       + ' (and non-forwards-filling) CSS Animations');
     div.remove();
     t.done();
   }));
 
   // Add a very short animation
   div.style.animation = 'anim1 0.01s';
-  window.getComputedStyle(div).animationName;
 }, 'getAnimationPlayers for CSS Animations that have finished');
 
 async_test(function(t) {
   var div = addDiv();
 
   // Set up event listener
   div.addEventListener('transitionend', t.step_func(function() {
     assert_equals(div.getAnimationPlayers().length, 0,
       'getAnimationPlayers does not return finished CSS Transitions');
     div.remove();
     t.done();
   }));
 
   // Add a very short transition
   div.style.left = '0px';
   window.getComputedStyle(div).left;
+
   div.style.transition = 'all 0.01s';
   div.style.left = '100px';
   window.getComputedStyle(div).left;
 }, 'getAnimationPlayers for CSS Transitions that have finished');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'none 100s';
-  window.getComputedStyle(div).animationName;
 
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 0,
     'getAnimationPlayers returns an empty sequence for an element'
     + ' with animation-name: none');
 
   div.style.animation = 'none 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
   players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns players only for those CSS Animations whose'
     + ' animation-name is not none');
 
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with animation-name: none');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'missing 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 0,
     'getAnimationPlayers returns an empty sequence for an element'
     + ' with animation-name: missing');
 
   div.style.animation = 'anim1 100s, missing 100s';
-  window.getComputedStyle(div).animationName;
   players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns players only for those CSS Animations whose'
     + ' animation-name is found');
 
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with animation-name: missing');
 
 async_test(function(t) {
   var div = addDiv();
   div.style.animation = 'anim1 100s, notyet 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers initally only returns players for CSS Animations whose'
     + ' animation-name is found');
 
   window.requestAnimationFrame(t.step_func(function() {
     var keyframes = '@keyframes notyet { to { left: 100px; } }';
     document.styleSheets[0].insertRule(keyframes, 0);
-    window.getComputedStyle(div).animationName;
-
     players = div.getAnimationPlayers();
     assert_equals(players.length, 2,
       'getAnimationPlayers includes player when @keyframes rule is added'
       + ' later');
     assert_true(players[0].startTime < players[1].startTime,
       'Newly added player has a later start time');
     document.styleSheets[0].deleteRule(0);
     div.remove();
     t.done();
   }));
 }, 'getAnimationPlayers for CSS Animations where the @keyframes rule is added'
    + ' later');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s, anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 2,
     'getAnimationPlayers returns one player for each CSS animation-name'
     + ' even if the names are duplicated');
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with duplicated animation-name');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'empty 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns players for CSS animations with an'
     + ' empty keyframes rule');
   div.remove();
 }, 'getAnimationPlayers for CSS Animations with empty keyframes rule');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s 100s';
-  window.getComputedStyle(div).animationName;
-
   var players = div.getAnimationPlayers();
   assert_equals(players.length, 1,
     'getAnimationPlayers returns animations for CSS animations whose'
     + ' delay makes them start later');
   assert_true(players[0].startTime <= document.timeline.currentTime,
     'For CSS Animations in delay phase, the start time of the player is'
     + ' not in the future');
   div.remove();
 }, 'getAnimationPlayers for CSS animations in delay phase');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 0s 100s';
-  window.getComputedStyle(div).animationName;
-
   assert_equals(div.getAnimationPlayers().length, 1,
     'getAnimationPlayers returns animations for CSS animations whose'
     + ' duration is zero');
   div.remove();
 }, 'getAnimationPlayers for zero-duration CSS Animations');
 
 test(function() {
   var div = addDiv();
 
   // Try to transition non-animatable property animation-duration
   div.style.animationDuration = '10s';
   window.getComputedStyle(div).animationDuration;
+
   div.style.transition = 'all 100s';
   div.style.animationDuration = '100s';
-  window.getComputedStyle(div).left;
 
   assert_equals(div.getAnimationPlayers().length, 0,
     'getAnimationPlayers returns an empty sequence for a transition'
     + ' of a non-animatable property');
   div.remove();
 }, 'getAnimationPlayers for transition on non-animatable property');
 
 test(function() {
   var div = addDiv();
 
   div.style.setProperty('-vendor-unsupported', '0px', '');
   window.getComputedStyle(div).transitionProperty;
   div.style.transition = 'all 100s';
   div.style.setProperty('-vendor-unsupported', '100px', '');
-  window.getComputedStyle(div).getPropertyValue('-vendor-unsupported');
 
   assert_equals(div.getAnimationPlayers().length, 0,
     'getAnimationPlayers returns an empty sequence for a transition'
     + ' of an unsupported property');
   div.remove();
 }, 'getAnimationPlayers for transition on unsupported property');
 
 test(function() {
   var div = addDiv();
   div.style.animation = 'anim1 100s';
-  window.getComputedStyle(div).animationName;
-
   var originalPlayer = div.getAnimationPlayers()[0];
 
   // Update pause state (an AnimationPlayer change)
   div.style.animationPlayState = 'paused';
-  window.getComputedStyle(div).animationPlayState;
   var pausedPlayer = div.getAnimationPlayers()[0];
   // FIXME: Check pausedPlayer.playState has changed once the API is available
   // (bug 1037321)
   assert_equals(originalPlayer, pausedPlayer,
                 'getAnimationPlayers returns the same objects even when their'
                 + ' play state changes');
 
   // Update duration (an Animation change)
   div.style.animationDuration = '200s';
-  window.getComputedStyle(div).animationDuration
   var extendedPlayer = div.getAnimationPlayers()[0];
   // FIXME: Check extendedPlayer.source.timing.duration has changed once the
   // API is available
   assert_equals(originalPlayer, extendedPlayer,
                 'getAnimationPlayers returns the same objects even when their'
                 + ' duration changes');
 
   div.remove();