Title: [225279] trunk
Revision
225279
Author
commit-qu...@webkit.org
Date
2017-11-29 11:05:10 -0800 (Wed, 29 Nov 2017)

Log Message

[iOS] Media controls should stop updating while media is playing in fullscreen
https://bugs.webkit.org/show_bug.cgi?id=180144
<rdar://problem/35060379>

Patch by Antoine Quint <grao...@apple.com> on 2017-11-29
Reviewed by Eric Carlson.

Source/WebCore:

Updating inline media controls while playing media in fullscreen is useless since we're guaranteed not to
have those controls visible, and hurtful since this has impact on battery life. To avoid this, we remove
all media event listeners while in fullscreen on iOS, which will prevent the UI to be udpated since all
updates are driven by media events.

To implement this, we remove the MediaControllerSupport destroy() method and make it a disable() method,
and factor code out of the MediaControllerSupport constructor into an enable() method that registers the
media event listeners. Then, as we enter and exit fullscreen, we call the disable() and enable() method
on the various MediaControllerSupport objects that were created to support the iOS inline media controls.

Test: media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html

* Modules/modern-media-controls/media/controls-visibility-support.js:
(ControlsVisibilitySupport):
(ControlsVisibilitySupport.prototype.enable):
(ControlsVisibilitySupport.prototype.disable):
(ControlsVisibilitySupport.prototype.destroy): Deleted.
* Modules/modern-media-controls/media/media-controller-support.js:
(MediaControllerSupport):
(MediaControllerSupport.prototype.enable):
(MediaControllerSupport.prototype.disable):
(MediaControllerSupport.prototype.destroy): Deleted.
* Modules/modern-media-controls/media/media-controller.js:
(MediaController.prototype.handleEvent):
(MediaController.prototype._updateControlsIfNeeded):
(MediaController.prototype._updateSupportingObjectsEnabledState):
(MediaController):

LayoutTests:

Add a new test that enters fullscreen, checks that the elapsed time shown in the inline media controls are the same
at this time and after a few "timeupdate" events, ensuring the DOM is no longer updated while in fullscreen, and then
exits fullscreen and checks that the elapsed time controls now update as expected. This test is skipped in OpenSource
since it uses touch events.

* media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen-expected.txt: Added.
* media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html: Added.
* platform/ios-simulator/TestExpectations:

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (225278 => 225279)


--- trunk/LayoutTests/ChangeLog	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/LayoutTests/ChangeLog	2017-11-29 19:05:10 UTC (rev 225279)
@@ -1,3 +1,20 @@
+2017-11-29  Antoine Quint  <grao...@apple.com>
+
+        [iOS] Media controls should stop updating while media is playing in fullscreen
+        https://bugs.webkit.org/show_bug.cgi?id=180144
+        <rdar://problem/35060379>
+
+        Reviewed by Eric Carlson.
+
+        Add a new test that enters fullscreen, checks that the elapsed time shown in the inline media controls are the same
+        at this time and after a few "timeupdate" events, ensuring the DOM is no longer updated while in fullscreen, and then
+        exits fullscreen and checks that the elapsed time controls now update as expected. This test is skipped in OpenSource
+        since it uses touch events.
+
+        * media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen-expected.txt: Added.
+        * media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
 2017-11-29  Simon Fraser  <simon.fra...@apple.com>
 
         Viewport unit values affected by Comand-+ zoom

Added: trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen-expected.txt (0 => 225279)


--- trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen-expected.txt	2017-11-29 19:05:10 UTC (rev 225279)
@@ -0,0 +1,25 @@
+Testing we stop updating controls while in fullscreen and then update them again when back to inline on iOS.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Obtained a 'play' event.
+
+Entering fullscreen.
+
+Obtained a webkitpresentationmodechanged event
+media.webkitDisplayingFullscreen = true.
+PASS media.paused is false
+
+Time progressed.
+PASS elapsedTimeWhenEnteringFullscreen === elapsedTime() is true
+
+Obtained a webkitpresentationmodechanged event
+media.webkitDisplayingFullscreen = false.
+PASS elapsedTimeWhenEnteringFullscreen === elapsedTime() became false
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html (0 => 225279)


--- trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html	                        (rev 0)
+++ trunk/LayoutTests/media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html	2017-11-29 19:05:10 UTC (rev 225279)
@@ -0,0 +1,86 @@
+<!DOCTYPE html>
+<script src=""
+<script src="" type="text/_javascript_"></script>
+<body>
+<video src="" style="width: 320px; height: 240px;" controls autoplay plays-inline></video>
+<script type="text/_javascript_">
+
+window.jsTestIsAsync = true;
+
+description("Testing we stop updating controls while in fullscreen and then update them again when back to inline on iOS.");
+
+const media = document.querySelector("video");
+const button = document.body.appendChild(document.createElement("button"));
+button.textContent = "Enter Fullscreen";
+button.style = "position: absolute; left: 0; top: 0";
+
+let elapsedTimeWhenEnteringFullscreen;
+
+media.addEventListener("webkitpresentationmodechanged", () => {
+    debug("");
+    debug("Obtained a webkitpresentationmodechanged event");
+    debug(`media.webkitDisplayingFullscreen = ${media.webkitDisplayingFullscreen}.`);
+
+    if (media.webkitDisplayingFullscreen) {
+        shouldBeFalse("media.paused");
+        elapsedTimeWhenEnteringFullscreen = elapsedTime();
+
+        // Let time progress and check after a while that we didn't update the tree.
+        let timeupdateEventCount = 0;
+        media.addEventListener("timeupdate", () => {
+            timeupdateEventCount++;
+            if (timeupdateEventCount == 5) {
+                debug("");
+                debug("Time progressed.");
+                shouldBeTrue("elapsedTimeWhenEnteringFullscreen === elapsedTime()");
+                media.pause();
+                media.webkitExitFullscreen();
+            }
+        });
+    } else
+        shouldBecomeEqual("elapsedTimeWhenEnteringFullscreen === elapsedTime()", "false", endTest);
+});
+
+media.addEventListener("play", () => {
+    debug("");
+    debug("Obtained a 'play' event.");
+
+    startTest();
+});
+
+function enterFullscreen() {
+    debug("");
+    debug("Entering fullscreen.");
+    button.addEventListener("click", () => {
+        try {
+            media.webkitEnterFullscreen();
+        } catch(e) {
+            debug("Toggling fullscreen failed.");
+            finishJSTest();
+        }
+    });
+
+    pressOnElement(button);
+}
+
+function elapsedTime()
+{
+    return window.internals.shadowRoot(media).querySelectorAll(".time-label")[0].textContent;
+}
+
+function startTest()
+{
+    enterFullscreen();
+}
+
+function endTest()
+{
+    debug("");
+    button.remove();
+    media.remove();
+    finishJSTest();
+}
+
+</script>
+<script src=""
+</body>

Modified: trunk/LayoutTests/platform/ios-simulator/TestExpectations (225278 => 225279)


--- trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/LayoutTests/platform/ios-simulator/TestExpectations	2017-11-29 19:05:10 UTC (rev 225279)
@@ -96,6 +96,7 @@
 media/modern-media-controls/button/button-active-state.html [ Skip ]
 media/modern-media-controls/fullscreen-support/fullscreen-support-press.html [ Skip ]
 media/modern-media-controls/media-controller/ios/media-controller-ios-only-enable-tap-gesture-recognizer-with-fades-when-idle.html [ Skip ]
+media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html [ Skip ]
 media/modern-media-controls/mute-support/mute-support-press-on-button.html [ Skip ]
 media/modern-media-controls/pip-support/ipad/pip-support-tap.html [ Skip ]
 media/modern-media-controls/placard-support/ipad [ Skip ]

Modified: trunk/Source/WebCore/ChangeLog (225278 => 225279)


--- trunk/Source/WebCore/ChangeLog	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/Source/WebCore/ChangeLog	2017-11-29 19:05:10 UTC (rev 225279)
@@ -1,3 +1,39 @@
+2017-11-29  Antoine Quint  <grao...@apple.com>
+
+        [iOS] Media controls should stop updating while media is playing in fullscreen
+        https://bugs.webkit.org/show_bug.cgi?id=180144
+        <rdar://problem/35060379>
+
+        Reviewed by Eric Carlson.
+
+        Updating inline media controls while playing media in fullscreen is useless since we're guaranteed not to
+        have those controls visible, and hurtful since this has impact on battery life. To avoid this, we remove
+        all media event listeners while in fullscreen on iOS, which will prevent the UI to be udpated since all
+        updates are driven by media events.
+
+        To implement this, we remove the MediaControllerSupport destroy() method and make it a disable() method,
+        and factor code out of the MediaControllerSupport constructor into an enable() method that registers the
+        media event listeners. Then, as we enter and exit fullscreen, we call the disable() and enable() method
+        on the various MediaControllerSupport objects that were created to support the iOS inline media controls.
+
+        Test: media/modern-media-controls/media-controller/ios/media-controller-stop-updates-in-fullscreen.html
+
+        * Modules/modern-media-controls/media/controls-visibility-support.js:
+        (ControlsVisibilitySupport):
+        (ControlsVisibilitySupport.prototype.enable):
+        (ControlsVisibilitySupport.prototype.disable):
+        (ControlsVisibilitySupport.prototype.destroy): Deleted.
+        * Modules/modern-media-controls/media/media-controller-support.js:
+        (MediaControllerSupport):
+        (MediaControllerSupport.prototype.enable):
+        (MediaControllerSupport.prototype.disable):
+        (MediaControllerSupport.prototype.destroy): Deleted.
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController.prototype.handleEvent):
+        (MediaController.prototype._updateControlsIfNeeded):
+        (MediaController.prototype._updateSupportingObjectsEnabledState):
+        (MediaController):
+
 2017-11-29  Simon Fraser  <simon.fra...@apple.com>
 
         Viewport unit values affected by Comand-+ zoom

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/controls-visibility-support.js (225278 => 225279)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/controls-visibility-support.js	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/controls-visibility-support.js	2017-11-29 19:05:10 UTC (rev 225279)
@@ -30,17 +30,31 @@
     {
         super(mediaController);
 
-        this._controlsAttributeObserver = new MutationObserver(this._updateControls.bind(this));
-        this._controlsAttributeObserver.observe(mediaController.media, { attributes: true, attributeFilter: ["controls"] });
-
         this._updateControls();
     }
 
     // Protected
 
-    destroy()
+    enable()
     {
+        super.enable();
+
+        if (this._controlsAttributeObserver)
+            return;
+
+        this._controlsAttributeObserver = new MutationObserver(this._updateControls.bind(this));
+        this._controlsAttributeObserver.observe(this.mediaController.media, { attributes: true, attributeFilter: ["controls"] });
+    }
+
+    disable()
+    {
+        super.disable();
+
+        if (!this._controlsAttributeObserver)
+            return;
+
         this._controlsAttributeObserver.disconnect();
+        delete this._controlsAttributeObserver;
     }
 
     get mediaEvents()

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js (225278 => 225279)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js	2017-11-29 19:05:10 UTC (rev 225279)
@@ -30,8 +30,15 @@
     {
         this.mediaController = mediaController;
 
+        this.enable();
+    }
+
+    // Public
+
+    enable()
+    {
         for (let eventType of this.mediaEvents)
-            mediaController.media.addEventListener(eventType, this);
+            this.mediaController.media.addEventListener(eventType, this);
 
         for (let tracks of this.tracksToMonitor) {
             for (let eventType of ["change", "addtrack", "removetrack"])
@@ -41,18 +48,14 @@
         if (!this.control)
             return;
 
+        this.control.uiDelegate = this;
         this.syncControl();
-
-        this.control.uiDelegate = this;
     }
 
-    // Public
-
-    destroy()
+    disable()
     {
-        const media = this.mediaController.media;
         for (let eventType of this.mediaEvents)
-            media.removeEventListener(eventType, this);
+            this.mediaController.media.removeEventListener(eventType, this);
 
         for (let tracks of this.tracksToMonitor) {
             for (let eventType of ["change", "addtrack", "removetrack"])

Modified: trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js (225278 => 225279)


--- trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js	2017-11-29 19:03:23 UTC (rev 225278)
+++ trunk/Source/WebCore/Modules/modern-media-controls/media/media-controller.js	2017-11-29 19:05:10 UTC (rev 225279)
@@ -158,6 +158,7 @@
             scheduler.flushScheduledLayoutCallbacks();
         } else if (event.currentTarget === this.media) {
             this._updateControlsIfNeeded();
+            this._updateSupportingObjectsEnabledState();
             if (event.type === "webkitpresentationmodechanged")
                 this._returnMediaLayerToInlineIfNeeded();
         } else if (event.type === "keydown" && this.isFullscreen && event.key === " ") {
@@ -179,11 +180,11 @@
             return;
         }
 
-        // Before we reset the .controls property, we need to destroy the previous
+        // Before we reset the .controls property, we need to disable the previous
         // supporting objects so we don't leak.
         if (this._supportingObjects) {
             for (let supportingObject of this._supportingObjects)
-                supportingObject.destroy();
+                supportingObject.disable();
         }
 
         this.controls = new ControlsClass;
@@ -248,4 +249,17 @@
         this.host.textTrackContainer.classList.toggle("visible-controls-bar", !this.controls.faded);
     }
 
+    _updateSupportingObjectsEnabledState()
+    {
+        // On iOS, we want to make sure not to update controls when we're in fullscreen since the UI
+        // will be completely invisible.
+        if (!(this.layoutTraits & LayoutTraits.iOS))
+            return;
+
+        if (this.isFullscreen)
+            this._supportingObjects.forEach(supportingObject => supportingObject.disable());
+        else
+            this._supportingObjects.forEach(supportingObject => supportingObject.enable());
+    }
+
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to