[Modern Media Controls] Media Controller: update controls based on fullscreen playbac...
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2016 15:43:53 +0000 (15:43 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 10 Nov 2016 15:43:53 +0000 (15:43 +0000)
https://bugs.webkit.org/show_bug.cgi?id=164554
<rdar://problem/29183439>

Patch by Antoine Quint <graouts@apple.com> on 2016-11-10
Reviewed by Dean Jackson.

Source/WebCore:

When toggling fullscreen on macOS, toggle between MacOSInlineMediaControls and MacOSFullscreenMediaControls.
To facilitate this, support objects are created and destroyed when changing the controls in order for the
right control objects to be hooked up to the media controller. A new destroy() method on MediaControllerSupport
subclasses can be overridden to remove event listeners added by support objects in their constructor.

Test: media/modern-media-controls/media-controller/media-controller-fullscreen-change.html

* Modules/modern-media-controls/media/fullscreen-support.js:
(FullscreenSupport.prototype.destroy):
* Modules/modern-media-controls/media/media-controller-support.js:
(MediaControllerSupport.prototype.destroy):
* Modules/modern-media-controls/media/media-controller.js:
(MediaController):
(MediaController.prototype.get layoutTraits):
(MediaController.prototype.handleEvent):
(MediaController.prototype._updateControlsIfNeeded):
(MediaController.prototype._controlsClass):

LayoutTests:

Adding a new test to check that we use fullscreen controls on macOS once we've entered fullscreen.

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

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@208537 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt [new file with mode: 0644]
LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/modern-media-controls/media/fullscreen-support.js
Source/WebCore/Modules/modern-media-controls/media/media-controller-support.js
Source/WebCore/Modules/modern-media-controls/media/media-controller.js

index 0334088..a0057a0 100644 (file)
@@ -1,3 +1,17 @@
+2016-11-10  Antoine Quint  <graouts@apple.com>
+
+        [Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=164554
+        <rdar://problem/29183439>
+
+        Reviewed by Dean Jackson.
+
+        Adding a new test to check that we use fullscreen controls on macOS once we've entered fullscreen.
+
+        * media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt: Added.
+        * media/modern-media-controls/media-controller/media-controller-fullscreen-change.html: Added.
+        * platform/ios-simulator/TestExpectations:
+
 2016-11-08  Sergio Villar Senin  <svillar@igalia.com>
 
         [css-grid] Fix fr tracks sizing under min|max-size constraints
diff --git a/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt b/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change-expected.txt
new file mode 100644 (file)
index 0000000..7004bb3
--- /dev/null
@@ -0,0 +1,17 @@
+Testing the MediaController behavior when entering and leaving fullscreen.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Media entered fullscreen
+PASS mediaController.layoutTraits is LayoutTraits.macOS | LayoutTraits.Fullscreen
+PASS mediaController.controls instanceof MacOSFullscreenMediaControls is true
+
+Media exited fullscreen
+PASS mediaController.layoutTraits is LayoutTraits.macOS
+PASS mediaController.controls instanceof MacOSInlineMediaControls is true
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html b/LayoutTests/media/modern-media-controls/media-controller/media-controller-fullscreen-change.html
new file mode 100644 (file)
index 0000000..28e4196
--- /dev/null
@@ -0,0 +1,64 @@
+<script src="../../../resources/js-test-pre.js"></script>
+<script src="../resources/media-controls-loader.js" type="text/javascript"></script>
+<body>
+<video src="../../content/test.mp4" style="width: 320px; height: 240px;"></video>
+<div id="shadow"></div>
+<script type="text/javascript">
+
+window.jsTestIsAsync = true;
+
+description("Testing the <code>MediaController</code> behavior when entering and leaving fullscreen.");
+
+const shadowRoot = document.querySelector("div#shadow").attachShadow({ mode: "open" });
+const media = document.querySelector("video");
+const mediaController = createControls(shadowRoot, media, null);
+
+const button = document.body.appendChild(document.createElement("button"));
+
+function enterFullscreen()
+{
+    if (!("eventSender" in window)) {
+        debug("This test is designed to run in DRT");
+        return;
+    }
+
+    // Click a button so we may enter fullscreen.
+    button.addEventListener("click", event => {
+        try {
+            media.webkitEnterFullscreen();
+        } catch(e) {
+            debug("Toggling fullscreen failed");
+            finishJSTest();
+        }
+    });
+
+    eventSender.mouseMoveTo(button.offsetLeft + 1, button.offsetTop + 1);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+media.addEventListener("webkitfullscreenchange", function() {
+    if (media.webkitDisplayingFullscreen) {
+        debug("Media entered fullscreen");
+        shouldBe("mediaController.layoutTraits", "LayoutTraits.macOS | LayoutTraits.Fullscreen");
+        shouldBeTrue("mediaController.controls instanceof MacOSFullscreenMediaControls");
+        debug("");
+        media.webkitExitFullscreen()
+    } else {
+        debug("Media exited fullscreen");
+        shouldBe("mediaController.layoutTraits", "LayoutTraits.macOS");
+        shouldBeTrue("mediaController.controls instanceof MacOSInlineMediaControls");
+
+        debug("");
+        shadowRoot.host.remove();
+        media.remove();
+        button.remove();
+        finishJSTest();
+    }
+});
+
+media.addEventListener("loadedmetadata", enterFullscreen);
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
index 4c9460b..8922419 100644 (file)
@@ -2748,3 +2748,6 @@ fast/layers/prevent-hit-test-during-layout.html [ Skip ]
 media/modern-media-controls/airplay-support/airplay-support.html [ Skip ]
 media/modern-media-controls/pip-support [ Skip ]
 media/modern-media-controls/placard-support [ Skip ]
+
+# This test is Mac-specific since it checks that we have custom controls in fullscreen.
+media/modern-media-controls/media-controller/media-controller-fullscreen-change.html [ Skip ]
index d849877..6f181ea 100644 (file)
@@ -1,3 +1,29 @@
+2016-11-10  Antoine Quint  <graouts@apple.com>
+
+        [Modern Media Controls] Media Controller: update controls based on fullscreen playback on macOS
+        https://bugs.webkit.org/show_bug.cgi?id=164554
+        <rdar://problem/29183439>
+
+        Reviewed by Dean Jackson.
+
+        When toggling fullscreen on macOS, toggle between MacOSInlineMediaControls and MacOSFullscreenMediaControls.
+        To facilitate this, support objects are created and destroyed when changing the controls in order for the
+        right control objects to be hooked up to the media controller. A new destroy() method on MediaControllerSupport
+        subclasses can be overridden to remove event listeners added by support objects in their constructor.
+
+        Test: media/modern-media-controls/media-controller/media-controller-fullscreen-change.html
+
+        * Modules/modern-media-controls/media/fullscreen-support.js:
+        (FullscreenSupport.prototype.destroy):
+        * Modules/modern-media-controls/media/media-controller-support.js:
+        (MediaControllerSupport.prototype.destroy):
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController):
+        (MediaController.prototype.get layoutTraits):
+        (MediaController.prototype.handleEvent):
+        (MediaController.prototype._updateControlsIfNeeded):
+        (MediaController.prototype._controlsClass):
+
 2016-11-10  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [Linux] Memory values shown by memory pressure handler logger are not useful
index 1b29ecb..b178679 100644 (file)
@@ -35,6 +35,17 @@ class FullscreenSupport extends MediaControllerSupport
             videoTracks.addEventListener(eventType, this);
     }
 
+    // Public
+
+    destroy()
+    {
+        super.destroy();
+
+        const videoTracks = this.mediaController.media.videoTracks;
+        for (let eventType of ["change", "addtrack", "removetrack"])
+            videoTracks.removeEventListener(eventType, this);
+    }
+
     // Protected
 
     get control()
index 3d4e1a7..d8272e3 100644 (file)
@@ -41,6 +41,18 @@ class MediaControllerSupport
         this.syncControl();
     }
 
+    // Public
+
+    destroy()
+    {
+        const media = this.mediaController.media;
+        for (let eventType of this.mediaEvents)
+            media.removeEventListener(eventType, this);
+
+        if (this.control)
+            this.control.uiDelegate = null;
+    }
+
     // Protected
 
     get control()
index 83bef53..01558bc 100644 (file)
@@ -32,28 +32,19 @@ class MediaController
         this.media = media;
         this.host = host;
 
-        // FIXME: This should get set dynamically based on the current environment.
-        this.layoutTraits = LayoutTraits.macOS;
-
-        this.controls = new MacOSInlineMediaControls
-        shadowRoot.appendChild(this.controls.element);        
-
-        new AirplaySupport(this);
-        new ElapsedTimeSupport(this);
-        new FullscreenSupport(this);
-        new MuteSupport(this);
-        new PiPSupport(this);
-        new PlacardSupport(this);
-        new PlaybackSupport(this);
-        new RemainingTimeSupport(this);
-        new ScrubbingSupport(this);
-        new SkipBackSupport(this);
-        new StartSupport(this);
-        new StatusSupport(this);
-        new VolumeSupport(this);
+        this._updateControlsIfNeeded();
 
-        this._updateControlsSize();
         media.addEventListener("resize", this);
+
+        media.addEventListener("webkitfullscreenchange", this);
+    }
+
+    get layoutTraits()
+    {
+        let traits = window.navigator.platform === "MacIntel" ? LayoutTraits.macOS : LayoutTraits.iOS;
+        if (this.media.webkitDisplayingFullscreen)
+            traits = traits | LayoutTraits.Fullscreen;
+        return traits;
     }
 
     // Protected
@@ -72,14 +63,52 @@ class MediaController
     {
         if (event.type === "resize" && event.currentTarget === this.media)
             this._updateControlsSize();
+        else if (event.type === "webkitfullscreenchange" && event.currentTarget === this.media)
+            this._updateControlsIfNeeded();
     }
 
     // Private
 
+    _updateControlsIfNeeded()
+    {
+        const previousControls = this.controls;
+        const ControlsClass = this._controlsClass();
+        if (previousControls && previousControls.constructor === ControlsClass)
+            return;
+
+        // Before we reset the .controls property, we need to destroy the previous
+        // supporting objects so we don't leak.
+        if (this._supportingObjects) {
+            for (let supportingObject of this._supportingObjects)
+                supportingObject.destroy();
+        }
+
+        this.controls = new ControlsClass;
+
+        if (previousControls)
+            this.shadowRoot.replaceChild(this.controls.element, previousControls.element);
+        else
+            this.shadowRoot.appendChild(this.controls.element);        
+
+        this._updateControlsSize();
+
+        this._supportingObjects = [AirplaySupport, ElapsedTimeSupport, FullscreenSupport, MuteSupport, PiPSupport, PlacardSupport, PlaybackSupport, RemainingTimeSupport, ScrubbingSupport, SkipBackSupport, StartSupport, StatusSupport, VolumeSupport].map(SupportClass => {
+            return new SupportClass(this);
+        }, this);
+    }
+
     _updateControlsSize()
     {
         this.controls.width = this.media.offsetWidth;
         this.controls.height = this.media.offsetHeight;
     }
 
+    _controlsClass()
+    {
+        const layoutTraits = this.layoutTraits;
+        if (layoutTraits & LayoutTraits.Fullscreen)
+            return MacOSFullscreenMediaControls;
+        return MacOSInlineMediaControls;
+    }
+
 }