Bug 1511235 - part2 : add test. r=jya,baku
authoralwu <alwu@mozilla.com>
Wed, 12 Dec 2018 02:16:55 +0000
changeset 450185 4c9f874d6868
parent 450184 3432e8bee7f1
child 450186 616721cad893
push id74553
push useralwu@mozilla.com
push dateWed, 12 Dec 2018 02:17:45 +0000
treeherderautoland@4c9f874d6868 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjya, baku
bugs1511235
milestone66.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 1511235 - part2 : add test. r=jya,baku Add new webidl method for testing only and a test. Differential Revision: https://phabricator.services.mozilla.com/D13805
dom/html/HTMLMediaElement.cpp
dom/html/HTMLMediaElement.h
dom/media/MediaDecoder.cpp
dom/media/MediaDecoder.h
dom/webidl/HTMLMediaElement.webidl
toolkit/content/tests/browser/browser.ini
toolkit/content/tests/browser/browser_suspend_videos_outside_viewport.js
toolkit/content/tests/browser/file_outside_viewport_videos.html
--- a/dom/html/HTMLMediaElement.cpp
+++ b/dom/html/HTMLMediaElement.cpp
@@ -1625,16 +1625,20 @@ already_AddRefed<Promise> HTMLMediaEleme
 
 void HTMLMediaElement::SetVisible(bool aVisible) {
   mForcedHidden = !aVisible;
   if (mDecoder) {
     mDecoder->SetForcedHidden(!aVisible);
   }
 }
 
+bool HTMLMediaElement::IsVideoDecodingSuspended() const {
+  return mDecoder && mDecoder->IsVideoDecodingSuspended();
+}
+
 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;
   }
--- a/dom/html/HTMLMediaElement.h
+++ b/dom/html/HTMLMediaElement.h
@@ -555,16 +555,19 @@ class HTMLMediaElement : public nsGeneri
   already_AddRefed<Promise> MozDumpDebugInfo();
 
   // For use by mochitests. Enabling pref "media.test.video-suspend"
   void SetVisible(bool aVisible);
 
   // For use by mochitests. Enabling pref "media.test.video-suspend"
   bool HasSuspendTaint() const;
 
+  // For use by mochitests. Enabling pref "media.test.video-suspend"
+  bool IsVideoDecodingSuspended() 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/MediaDecoder.cpp
+++ b/dom/media/MediaDecoder.cpp
@@ -430,19 +430,21 @@ void MediaDecoder::OnPlaybackEvent(Media
     case MediaPlaybackEvent::SeekStarted:
       SeekingStarted();
       break;
     case MediaPlaybackEvent::Invalidate:
       Invalidate();
       break;
     case MediaPlaybackEvent::EnterVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozentervideosuspend"));
+      mIsVideoDecodingSuspended = true;
       break;
     case MediaPlaybackEvent::ExitVideoSuspend:
       GetOwner()->DispatchAsyncEvent(NS_LITERAL_STRING("mozexitvideosuspend"));
+      mIsVideoDecodingSuspended = false;
       break;
     case MediaPlaybackEvent::StartVideoSuspendTimer:
       GetOwner()->DispatchAsyncEvent(
           NS_LITERAL_STRING("mozstartvideosuspendtimer"));
       break;
     case MediaPlaybackEvent::CancelVideoSuspendTimer:
       GetOwner()->DispatchAsyncEvent(
           NS_LITERAL_STRING("mozcancelvideosuspendtimer"));
@@ -455,16 +457,20 @@ void MediaDecoder::OnPlaybackEvent(Media
       GetOwner()->DispatchAsyncEvent(
           NS_LITERAL_STRING("mozvideoonlyseekcompleted"));
       break;
     default:
       break;
   }
 }
 
+bool MediaDecoder::IsVideoDecodingSuspended() const {
+  return mIsVideoDecodingSuspended;
+}
+
 void MediaDecoder::OnPlaybackErrorEvent(const MediaResult& aError) {
   DecodeError(aError);
 }
 
 void MediaDecoder::OnDecoderDoctorEvent(DecoderDoctorEvent aEvent) {
   MOZ_ASSERT(NS_IsMainThread());
   // OnDecoderDoctorEvent is disconnected at shutdown time.
   MOZ_DIAGNOSTIC_ASSERT(!IsShutdown());
--- a/dom/media/MediaDecoder.h
+++ b/dom/media/MediaDecoder.h
@@ -307,16 +307,18 @@ class MediaDecoder : public DecoderDocto
 
   // Returns true if the decoder can't participate in suspend-video-decoder.
   bool HasSuspendTaint() const;
 
   void UpdateVideoDecodeMode();
 
   void SetIsBackgroundVideoDecodingAllowed(bool aAllowed);
 
+  bool IsVideoDecodingSuspended() const;
+
   /******
    * The following methods must only be called on the main
    * thread.
    ******/
 
   // Change to a new play state. This updates the mState variable and
   // notifies any thread blocking on this object's monitor of the
   // change. Call on the main thread only.
@@ -573,16 +575,19 @@ class MediaDecoder : public DecoderDocto
   MediaEventListener mOnPlaybackErrorEvent;
   MediaEventListener mOnDecoderDoctorEvent;
   MediaEventListener mOnMediaNotSeekable;
   MediaEventListener mOnEncrypted;
   MediaEventListener mOnWaitingForKey;
   MediaEventListener mOnDecodeWarning;
   MediaEventListener mOnNextFrameStatus;
 
+  // True if we have suspended video decoding.
+  bool mIsVideoDecodingSuspended = false;
+
  protected:
   // PlaybackRate and pitch preservation status we should start at.
   double mPlaybackRate;
 
   // True if the decoder is seeking.
   Watchable<bool> mLogicallySeeking;
 
   // Buffered range, mirrored from the reader.
--- a/dom/webidl/HTMLMediaElement.webidl
+++ b/dom/webidl/HTMLMediaElement.webidl
@@ -213,16 +213,20 @@ partial interface HTMLMediaElement {
  *   drawImage().
  */
 partial interface HTMLMediaElement {
   [Pref="media.test.video-suspend"]
   void setVisible(boolean aVisible);
 
   [Pref="media.test.video-suspend"]
   boolean hasSuspendTaint();
+
+  [ChromeOnly]
+  // This one is used for testing only
+  readonly attribute boolean isVideoDecodingSuspended;
 };
 
 /* Audio Output Devices API */
 partial interface HTMLMediaElement {
   [Pref="media.setsinkid.enabled"]
   readonly attribute DOMString sinkId;
   [Throws, Pref="media.setsinkid.enabled"]
   Promise<void> setSinkId(DOMString sinkId);
--- a/toolkit/content/tests/browser/browser.ini
+++ b/toolkit/content/tests/browser/browser.ini
@@ -98,16 +98,20 @@ uses-unsafe-cpows = true
 [browser_default_image_filename.js]
 [browser_default_image_filename_redirect.js]
 [browser_f7_caret_browsing.js]
 [browser_findbar.js]
 [browser_findbar_disabled_manual.js]
 [browser_isSynthetic.js]
 [browser_keyevents_during_autoscrolling.js]
 [browser_label_textlink.js]
+[browser_suspend_videos_outside_viewport.js]
+support-files =
+  file_outside_viewport_videos.html
+  gizmo.mp4
 [browser_mediaPlayback.js]
 tags = audiochannel
 [browser_mediaPlayback_mute.js]
 tags = audiochannel
 [browser_mediaPlayback_suspended.js]
 tags = audiochannel
 [browser_mediaPlayback_suspended_multipleAudio.js]
 tags = audiochannel
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/browser_suspend_videos_outside_viewport.js
@@ -0,0 +1,33 @@
+/**
+ * This test is used to ensure we suspend video decoding if video is not in the
+ * viewport.
+ */
+"use strict";
+
+const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_outside_viewport_videos.html";
+
+async function test_suspend_video_decoding() {
+  let videos = content.document.getElementsByTagName("video");
+  for (let video of videos) {
+    info(`- start video on the ${video.id} side and outside the viewport -`);
+    await video.play();
+    ok(true, `video started playing`);
+    ok(video.isVideoDecodingSuspended, `video decoding is suspended`);
+  }
+}
+
+add_task(async function setup_test_preference() {
+  await SpecialPowers.pushPrefEnv({"set": [
+    ["media.suspend-bkgnd-video.enabled", true],
+    ["media.suspend-bkgnd-video.delay-ms", 0],
+  ]});
+});
+
+add_task(async function start_test() {
+  await BrowserTestUtils.withNewTab({
+    gBrowser,
+    url: PAGE,
+  }, async browser => {
+    await ContentTask.spawn(browser, null, test_suspend_video_decoding);
+  });
+});
new file mode 100644
--- /dev/null
+++ b/toolkit/content/tests/browser/file_outside_viewport_videos.html
@@ -0,0 +1,41 @@
+<html>
+<head>
+  <title>outside viewport videos</title>
+<style>
+/**
+ * These CSS would move elements to the far left/right/top/bottom where user
+ * can not see elements in the viewport if user doesn't scroll the page.
+ */
+.outside-left {
+  position: absolute;
+  left: -200%;
+}
+.outside-right {
+  position: absolute;
+  right: -200%;
+}
+.outside-top {
+  position: absolute;
+  top: -200%;
+}
+.outside-bottom {
+  position: absolute;
+  bottom: -200%;
+}
+</style>
+</head>
+<body>
+	<div class="outside-left">
+		<video id="left" src="gizmo.mp4">
+	</div>
+	<div class="outside-right">
+		<video id="right" src="gizmo.mp4">
+	</div>
+	<div class="outside-top">
+		<video id="top" src="gizmo.mp4">
+	</div>
+	<div class="outside-bottom">
+		<video id="bottom" src="gizmo.mp4">
+	</div>
+</body>
+</html>