Bug 1309494 part 2 - implement the show throbber mechanism; r?jaws draft
authorKaku Kuo <kaku@mozilla.com>
Mon, 13 Mar 2017 11:29:39 +0800
changeset 497470 dcf2144b3f8ec5deaaed74117abbaa0a31a66141
parent 497469 6cb17b91aeb9530734c6a15fa3227c12d2209ea3
child 548904 46a9b93464470c8e914cb1aca0456af7c2f6f2c1
push id48917
push userbmo:kaku@mozilla.com
push dateMon, 13 Mar 2017 11:42:30 +0000
reviewersjaws
bugs1309494
milestone55.0a1
Bug 1309494 part 2 - implement the show throbber mechanism; r?jaws MozReview-Commit-ID: 1UKAYu0xy9u
toolkit/content/widgets/videocontrols.xml
--- a/toolkit/content/widgets/videocontrols.xml
+++ b/toolkit/content/widgets/videocontrols.xml
@@ -280,21 +280,26 @@
         }
 
         // Explicitly hide the status fader if this
         // is audio only until bug 619421 is fixed.
         if (this.isAudioOnly) {
           show = false;
         }
 
+        if (this._showThrobberTimer) {
+          show = true;
+        }
+
         this.log("Status overlay: seeking=" + this.video.seeking +
                  " error=" + this.video.error + " readyState=" + this.video.readyState +
                  " paused=" + this.video.paused + " ended=" + this.video.ended +
                  " networkState=" + this.video.networkState +
                  " timeUpdateCount=" + this.timeUpdateCount +
+                 " _showThrobberTimer=" + this._showThrobberTimer +
                  " --> " + (show ? "SHOW" : "HIDE"));
         this.startFade(this.statusOverlay, show, immediate);
       },
 
       /*
       * Set the initial state of the controls. The binding is normally created along
       * with video element, but could be attached at any point (eg, if the video is
       * removed from the document and then reinserted). Thus, some one-time events may
@@ -488,16 +493,47 @@
 
       updateVolumeControls() {
         var volume = this.video.muted ? 0 : this.video.volume;
         var volumePercentage = Math.round(volume * 100);
         this.updateMuteButtonState();
         this.volumeControl.value = volumePercentage;
       },
 
+      /*
+       * We suspend a video element's video decoder if the video
+       * element is invisible. However, resuming the video decoder
+       * takes time and we show the throbber UI if it takes more than
+       * 250 ms.
+       *
+       * When an already-suspended video element becomes visible, we
+       * resume its video decoder immediately and queue a seek task to
+       * seek the resumed video decoder to the current position;
+       * meanwhile, we also file a "mozexitvideosuspend" event which
+       * we used to start the timer here.
+       *
+       * Once the queued seek operation is done, we dispatch a
+       * "canplay" event which indicates that the resuming operation
+       * is completed.
+       */
+      SHOW_THROBBER_TIMEOUT_MS: 250,
+      _showThrobberTimer: null,
+      _delayShowThrobberWhileResumingVideoDecoder() {
+          this._showThrobberTimer = setTimeout(() => {
+              this.statusIcon.setAttribute("type", "throbber");
+              this.setupStatusFader();
+          }, this.SHOW_THROBBER_TIMEOUT_MS);
+      },
+      _cancelShowThrobberWhileResumingVideoDecoder() {
+          if (this._showThrobberTimer) {
+            clearTimeout(this._showThrobberTimer);
+            this._showThrobberTimer = null;
+          }
+      },
+
       handleEvent(aEvent) {
         this.log("Got media event ----> " + aEvent.type);
 
         // If the binding is detached (or has been replaced by a
         // newer instance of the binding), nuke our event-listeners.
         if (this.videocontrols.randomID != this.randomID) {
           this.terminateEventListeners();
           return;
@@ -633,16 +669,17 @@
             break;
           case "waiting":
             this.statusIcon.setAttribute("type", "throbber");
             this.setupStatusFader();
             break;
           case "seeked":
           case "playing":
           case "canplay":
+            this._cancelShowThrobberWhileResumingVideoDecoder();
           case "canplaythrough":
             this.setupStatusFader();
             break;
           case "error":
             // We'll show the error status icon when we receive an error event
             // under either of the following conditions:
             // 1. The video has its error attribute set; this means we're loading
             //    from our src attribute, and the load failed, or we we're loading
@@ -660,16 +697,17 @@
               // If video hasn't shown anything yet, disable the controls.
               if (!this.firstFrameShown) {
                 this.startFadeOut(this.controlBar);
               }
               this.controlsSpacer.removeAttribute("hideCursor");
             }
             break;
           case "mozexitvideosuspend":
+            this._delayShowThrobberWhileResumingVideoDecoder();
             break;
           default:
             this.log("!!! event " + aEvent.type + " not handled!");
         }
       },
 
       terminateEventListeners() {
         if (this.videoEvents) {