Bug 1511235 - Part 3: Ensure video is visible before starting test. r=jya,baku, a=RyanVM
authorAlastor Wu <alwu@mozilla.com>
Fri, 21 Dec 2018 06:40:10 +0000
changeset 506426 49db147e8a5c
parent 506425 9d3238bbfcc6
child 506427 1d747c8ca942
push id10410
push userryanvm@gmail.com
push dateSun, 30 Dec 2018 23:47:52 +0000
treeherdermozilla-beta@1d747c8ca942 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya, baku, RyanVM
bugs1511235
milestone65.0
Bug 1511235 - Part 3: Ensure video is visible before starting test. r=jya,baku, a=RyanVM Add testing function to know whether video is visible or not. Differential Revision: https://phabricator.services.mozilla.com/D14667
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/test/background_video.js
dom/media/test/test_background_video_cancel_suspend_taint.html
dom/webidl/HTMLMediaElement.webidl
modules/libpref/init/StaticPrefList.h
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1629,16 +1629,20 @@ void HTMLMediaElement::SetVisible(bool a
     mDecoder->SetForcedHidden(!aVisible);
   }
 }
 
 bool HTMLMediaElement::IsVideoDecodingSuspended() const {
   return mDecoder && mDecoder->IsVideoDecodingSuspended();
 }
 
+bool HTMLMediaElement::IsVisible() const {
+  return mVisibilityState == Visibility::APPROXIMATELY_VISIBLE;
+}
+
 already_AddRefed<layers::Image> HTMLMediaElement::GetCurrentImage() {
   MarkAsTainted();
 
   // TODO: In bug 1345404, handle case when video decoder is already suspended.
   ImageContainer* container = GetImageContainer();
   if (!container) {
     return nullptr;
   }
@@ -6273,16 +6277,19 @@ static const char* VisibilityString(Visi
   return "NAN";
 }
 
 void HTMLMediaElement::OnVisibilityChange(Visibility aNewVisibility) {
   LOG(LogLevel::Debug,
       ("OnVisibilityChange(): %s\n", VisibilityString(aNewVisibility)));
 
   mVisibilityState = aNewVisibility;
+  if (StaticPrefs::MediaTestVideoSuspend()) {
+    DispatchAsyncEvent(NS_LITERAL_STRING("visibilitychanged"));
+  }
 
   if (!mDecoder) {
     return;
   }
 
   switch (aNewVisibility) {
     case Visibility::UNTRACKED: {
       MOZ_ASSERT_UNREACHABLE("Shouldn't notify for untracked visibility");
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -558,16 +558,19 @@ class HTMLMediaElement : public nsGeneri
   void SetVisible(bool aVisible);
 
   // For use by mochitests. Enabling pref "media.test.video-suspend"
   bool HasSuspendTaint() const;
 
   // For use by mochitests.
   bool IsVideoDecodingSuspended() const;
 
+  // For use by mochitests only.
+  bool IsVisible() const;
+
   // Synchronously, return the next video frame and mark the element unable to
   // participate in decode suspending.
   //
   // This function is synchronous for cases where decoding has been suspended
   // and JS needs a frame to use in, eg., nsLayoutUtils::SurfaceFromElement()
   // via drawImage().
   already_AddRefed<layers::Image> GetCurrentImage();
 
--- a/dom/media/test/background_video.js
+++ b/dom/media/test/background_video.js
@@ -43,16 +43,38 @@ function appendVideoToDoc(url, token, wi
   v.token = token;
   v.width = width;
   v.height = height;
   v.src = url;
   document.body.appendChild(v);
   return v;
 }
 
+
+/**
+ * @param {HTMLMediaElement} video Video element with under test.
+ * @returns {Promise} Promise that is resolved when video 'visibilitychanged' event fires.
+ */
+function waitUntilVisible(video) {
+  let videoChrome = SpecialPowers.wrap(video);
+  if (videoChrome.isVisible) {
+    return Promise.resolve();
+  }
+
+  return new Promise(resolve => {
+    videoChrome.addEventListener("visibilitychanged", () => {
+      if (videoChrome.isVisible) {
+        ok(true, `${video.token} is visible.`);
+        videoChrome.removeEventListener("visibilitychanged", this);
+        resolve();
+      }
+    });
+  });
+}
+
 /**
  * @param {HTMLMediaElement} video Video element under test.
  * @returns {Promise} Promise that is resolved when video 'playing' event fires.
  */
 function waitUntilPlaying(video) {
   var p = once(video, 'playing', () => { ok(true, `${video.token} played.`); });
   Log(video.token, "Start playing");
   video.play();
--- a/dom/media/test/test_background_video_cancel_suspend_taint.html
+++ b/dom/media/test/test_background_video_cancel_suspend_taint.html
@@ -55,15 +55,16 @@ startTest({
     [ "media.suspend-bkgnd-video.enabled", true ],
     [ "media.suspend-bkgnd-video.delay-ms", 10000 ]
   ],
   tests: gDecodeSuspendTests,
   runTest: (test, token) => {
     let v = appendVideoToDoc(test.name, token);
     manager.started(token);
 
-    waitUntilPlaying(v)
+    waitUntilVisible(v)
+      .then(() => waitUntilPlaying(v))
       .then(() => testSuspendTimerStartedWhenHidden(v))
       .then(() => testSuspendTimerCanceledWhenTainted(v))
       .then(() => { manager.finished(token); });
   }
 });
-</script>
\ No newline at end of file
+</script>
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -206,26 +206,30 @@ partial interface HTMLMediaElement {
 /*
  * These APIs are testing only, they are used to simulate visibility changes to help debug and write
  * tests about suspend-video-decoding.
  *
  * - SetVisible() is for simulating visibility changes.
  * - HasSuspendTaint() is for querying that the element's decoder cannot suspend
  *   video decoding because it has been tainted by an operation, such as
  *   drawImage().
+ * - isVisible is a boolean value which indicate whether media element is visible.
  * - isVideoDecodingSuspended() is used to know whether video decoding has suspended.
  */
 partial interface HTMLMediaElement {
   [Pref="media.test.video-suspend"]
   void setVisible(boolean aVisible);
 
   [Pref="media.test.video-suspend"]
   boolean hasSuspendTaint();
 
   [ChromeOnly]
+  readonly attribute boolean isVisible;
+
+  [ChromeOnly]
   readonly attribute boolean isVideoDecodingSuspended;
 };
 
 /* Audio Output Devices API */
 partial interface HTMLMediaElement {
   [Pref="media.setsinkid.enabled"]
   readonly attribute DOMString sinkId;
   [Throws, Pref="media.setsinkid.enabled"]
--- a/modules/libpref/init/StaticPrefList.h
+++ b/modules/libpref/init/StaticPrefList.h
@@ -1552,16 +1552,22 @@ VARCACHE_PREF(
 )
 
 VARCACHE_PREF(
   "media.benchmark.timeout",
    MediaBenchmarkTimeout,
   RelaxedAtomicUint32, 1000
 )
 
+VARCACHE_PREF(
+  "media.test.video-suspend",
+   MediaTestVideoSuspend,
+  RelaxedAtomicBool, false
+)
+
 //---------------------------------------------------------------------------
 // Network prefs
 //---------------------------------------------------------------------------
 
 // Sub-resources HTTP-authentication:
 //   0 - don't allow sub-resources to open HTTP authentication credentials
 //       dialogs
 //   1 - allow sub-resources to open HTTP authentication credentials dialogs,