Bug 1449532 - Part III, Polyfill Web Animation API features draft
authorTimothy Guan-tin Chien <timdream@gmail.com>
Sat, 31 Mar 2018 11:31:36 +0800
changeset 777044 bd34dfc95c73c05f0c9ca97de0867bf6725b111e
parent 777043 41ec315236cf27b84b59b821af81fe1d3f0093f2
child 777045 56e1f6fd217fb5b78cf97c225d8f4e872b1167de
child 777049 4e9aa4ac7b49f4b27b8805b18e28bed57eb8c430
push id105061
push usertimdream@gmail.com
push dateWed, 04 Apr 2018 05:03:48 +0000
bugs1449532
milestone61.0a1
Bug 1449532 - Part III, Polyfill Web Animation API features 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;
 }