Bug 1449532 - Part III, Polyfill Web Animation API features r=Gijs
authorTimothy Guan-tin Chien <timdream@gmail.com>
Sat, 31 Mar 2018 11:31:36 +0800
changeset 411646 64486670492f5c9cc2e890c5931284bb6a85d194
parent 411645 62e9d302879c70dd6e379c7620d642ad011feb39
child 411647 545bb9b8a294def427902f5faa66b91ca56686b9
push id33764
push usercsabou@mozilla.com
push dateWed, 04 Apr 2018 17:53:18 +0000
treeherdermozilla-central@90eb45ff0a64 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersGijs
bugs1449532
milestone61.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 1449532 - Part III, Polyfill Web Animation API features r=Gijs The Animation and KeyframeEffect constructors and the finshed promise are not enabled on release channel currently. The polyfill is added to make sure we don't break on release. When the feature ships, removing the polyfill should be as easy as reverting this changeset. MozReview-Commit-ID: 2EWN7hBN5tj
toolkit/content/widgets/videocontrols.xml
toolkit/themes/shared/media/videocontrols.css
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -1018,16 +1018,42 @@
             { opacity: 1 }
           ],
           options: {
             duration: 1050
           }
         }
       },
 
+      // Polyfill animation.finished promise, also invalidate
+      // the previous promise.
+      // Remove when the platform implementation ships.
+      // (currently behind dom.animations-api.core.enabled)
+      installFinishedPromisePolyfill(animation) {
+        let handler = {
+          handleEvent(evt) {
+            animation.removeEventListener("finish", this);
+            animation.removeEventListener("cancel", this);
+            if (evt.type == "finish" &&
+                this === animation.finished) {
+              this.fn();
+            }
+          },
+          then(fn) {
+            this.fn = fn;
+          }
+        };
+        // Note that handler is not a real Promise.
+        // All it offered is a then() method to register a callback
+        // to be triggered at the right time.
+        animation.finished = handler;
+        animation.addEventListener("finish", handler);
+        animation.addEventListener("cancel", handler);
+      },
+
       startFade(element, fadeIn, immediate = false) {
         // Bug 493523, the scrubber doesn't call valueChanged while hidden,
         // so our dependent state (eg, timestamp in the thumb) will be stale.
         // As a workaround, update it manually when it first becomes unhidden.
         if (element == this.controlBar && fadeIn && element.hidden) {
           this.scrubber.value = this.video.currentTime * 1000;
         }
 
@@ -1035,18 +1061,25 @@
           this.animationProps[element.getAttribute("anonid")];
         if (!animationProp) {
           throw new Error("Element " + element.getAttribute("anonid") +
             " has no transition. Toggle the hidden property directly.");
         }
 
         let animation = this.animationMap.get(element);
         if (!animation) {
+          // Create the animation object but don't start it.
+          // To be replaced with the following when the constructors ship
+          // (currently behind dom.animations-api.core.enabled)
+          /*
           animation = new Animation(new KeyframeEffect(
             element, animationProp.keyframes, animationProp.options));
+          */
+          animation = element.animate(animationProp.keyframes, animationProp.options);
+          animation.cancel();
 
           this.animationMap.set(element, animation);
         }
 
         if (fadeIn) {
           // hidden state should be controlled by adjustControlSize
           if (element.isAdjustableControl && element.hiddenByAdjustment) {
             return;
@@ -1072,16 +1105,17 @@
         }
 
         element.classList.toggle("fadeout", !fadeIn);
         element.classList.toggle("fadein", fadeIn);
         let finishedPromise;
         if (!immediate) {
           animation.playbackRate = fadeIn ? 1 : -1;
           animation.play();
+          this.installFinishedPromisePolyfill(animation);
           finishedPromise = animation.finished;
         } else {
           animation.cancel();
           finishedPromise = Promise.resolve();
         }
         finishedPromise.then(() => {
           if (element == this.controlBar) {
             this.onControlBarAnimationFinished();
--- a/toolkit/themes/shared/media/videocontrols.css
+++ b/toolkit/themes/shared/media/videocontrols.css
@@ -60,16 +60,26 @@ audio > xul|videocontrols {
 
 .touch .controlBar {
   /* Do not delete: these variables are accessed by JavaScript directly.
      see videocontrols.xml and search for |-width|. */
   --scrubberStack-width: 84px;
   --volumeStack-width: 64px;
 }
 
+/*
+  XXX this is needed because of bug 1354501.
+  Can be removed when the bug is fixed, or when we move away from
+  the finish event to the finished promise.
+  (currently behind dom.animations-api.core.enabled)
+*/
+.fadeout {
+  opacity: 0;
+}
+
 .controlsContainer [hidden],
 .controlBar[hidden] {
   display: none;
 }
 
 .controlBar[size="hidden"] {
   display: none;
 }