[Modern Media Controls] Show and populate the tracks panel
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Dec 2016 02:07:35 +0000 (02:07 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Dec 2016 02:07:35 +0000 (02:07 +0000)
https://bugs.webkit.org/show_bug.cgi?id=165284

Reviewed by Dean Jackson.

We added a TracksPanel in https://bugs.webkit.org/show_bug.cgi?id=165239 which allows to
show a list of media tracks and text tracks to choose from. We now show this panel when
clicking on the tracks button in the controls bar and populate its content with the
list of audio and text tracks for the media element. As an item is picked from the tracks
panel, we toggle the represented track's enabled state and dismiss the panel.

We also pick up the text track container display mostly unchanged from current media controls.

Tests: media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html
       media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html

* Modules/modern-media-controls/controls/macos-inline-media-controls.js:
(MacOSInlineMediaControls.prototype.showTracksPanel):
* Modules/modern-media-controls/controls/text-tracks.css: Added.
(video::-webkit-media-text-track-container):
(video::cue):
(video::-webkit-media-text-track-display):
(video::-webkit-media-text-track-display-backdrop):
(video::cue(:future)):
(video::-webkit-media-text-track-container b):
(video::-webkit-media-text-track-container u):
(video::-webkit-media-text-track-container i):
(video::-webkit-media-text-track-container .hidden):
* Modules/modern-media-controls/media/media-controller.js:
(MediaController):
* Modules/modern-media-controls/media/tracks-support.js:
(TracksSupport):
(TracksSupport.prototype.destroy):
(TracksSupport.prototype.buttonWasClicked):
(TracksSupport.prototype.tracksPanelNumberOfSections):
(TracksSupport.prototype.tracksPanelTitleForSection):
(TracksSupport.prototype.tracksPanelNumberOfTracksInSection):
(TracksSupport.prototype.tracksPanelTitleForTrackInSection):
(TracksSupport.prototype.tracksPanelIsTrackInSectionSelected):
(TracksSupport.prototype.tracksPanelSelectionDidChange):
(TracksSupport.prototype.syncControl):
(TracksSupport.prototype._textTracks):
(TracksSupport.prototype._audioTracks):
(TracksSupport.prototype._canPickAudioTracks):
(TracksSupport.prototype._canPickTextTracks):
(TracksSupport.prototype._sortedTrackList):

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

12 files changed:
LayoutTests/ChangeLog
LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel-expected.txt [new file with mode: 0644]
LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html [new file with mode: 0644]
LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel-expected.txt [new file with mode: 0644]
LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html [new file with mode: 0644]
LayoutTests/platform/ios-simulator/TestExpectations
LayoutTests/platform/mac/TestExpectations
Source/WebCore/ChangeLog
Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.js
Source/WebCore/Modules/modern-media-controls/controls/text-tracks.css [new file with mode: 0644]
Source/WebCore/Modules/modern-media-controls/media/media-controller.js
Source/WebCore/Modules/modern-media-controls/media/tracks-support.js

index 4439f12..150062e 100644 (file)
@@ -1,3 +1,19 @@
+2016-12-01  Antoine Quint  <graouts@apple.com>
+
+        [Modern Media Controls] Show and populate the tracks panel
+        https://bugs.webkit.org/show_bug.cgi?id=165284
+
+        Reviewed by Dean Jackson.
+
+        Add two new tests to check that we correctly show, populate and interact with the tracks panel.
+
+        * media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel-expected.txt: Added.
+        * media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html: Added.
+        * media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel-expected.txt: Added.
+        * media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html: Added.
+        * platform/ios-simulator/TestExpectations:
+        * platform/mac/TestExpectations:
+
 2016-12-01  Ryan Haddad  <ryanhaddad@apple.com>
 
         Removing Release-only flag from flaky test http/tests/cache/disk-cache/disk-cache-request-max-stale.html
diff --git a/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel-expected.txt b/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel-expected.txt
new file mode 100644 (file)
index 0000000..3f13952
--- /dev/null
@@ -0,0 +1,16 @@
+Clicking on a track in the tracks panel.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS media.audioTracks[1].enabled is false
+
+Clicking on the tracks button
+Clicking on second audio track in tracks panel
+Obtained change event on media audio tracks
+PASS media.audioTracks[1].enabled is true
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html b/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html
new file mode 100644 (file)
index 0000000..dda1ec4
--- /dev/null
@@ -0,0 +1,58 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableModernMediaControls=true ] -->
+<script src="../../../resources/js-test-pre.js"></script>
+<body>
+<video src="../../content/CC+Subtitles.mov" style="width: 640px; height: 360px;" controls autoplay></video>
+<script type="text/javascript">
+
+window.jsTestIsAsync = true;
+
+description("Clicking on a track in the tracks panel.");
+
+const media = document.querySelector("video");
+const shadowRoot = window.internals.shadowRoot(media);
+
+media.addEventListener("play", () => {
+    media.pause();
+
+    shouldBeFalse("media.audioTracks[1].enabled");
+    debug("");
+
+    media.audioTracks.addEventListener("change", audioTracksDidChange);
+    window.requestAnimationFrame(() => {
+        clickOnTracksButton();
+        window.requestAnimationFrame(clickOnSecondAudioTrack);
+    });
+});
+
+function clickOnTracksButton()
+{
+    debug("Clicking on the tracks button");
+    const bounds = shadowRoot.lastChild.querySelector("button.tracks").getBoundingClientRect();
+    eventSender.mouseMoveTo(bounds.left + 1, bounds.top + 1);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+function clickOnSecondAudioTrack()
+{
+    debug("Clicking on second audio track in tracks panel");
+    const secondAudioTrack = shadowRoot.lastChild.querySelectorAll("li")[1];
+    const bounds = secondAudioTrack.getBoundingClientRect();
+    eventSender.mouseMoveTo(bounds.left + 1, bounds.top + 1);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+function audioTracksDidChange()
+{
+    debug("Obtained change event on media audio tracks");
+    shouldBeTrue("media.audioTracks[1].enabled");
+
+    debug("");
+    media.remove();
+    finishJSTest();
+}
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
diff --git a/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel-expected.txt b/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel-expected.txt
new file mode 100644 (file)
index 0000000..052d6cb
--- /dev/null
@@ -0,0 +1,22 @@
+Showing and populating the tracks panel.
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Audio
+  English Sound
+  French Sound
+  Spanish Sound
+
+Subtitles
+  Off
+  Auto (Recommended)
+  English Subtitles
+  French Subtitles
+  German Subtitles
+  Spanish Subtitles
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html b/LayoutTests/media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html
new file mode 100644 (file)
index 0000000..5845b62
--- /dev/null
@@ -0,0 +1,46 @@
+<!DOCTYPE html><!-- webkit-test-runner [ enableModernMediaControls=true ] -->
+<script src="../../../resources/js-test-pre.js"></script>
+<body>
+<video src="../../content/CC+Subtitles.mov" style="width: 640px; height: 360px;" controls autoplay></video>
+<script type="text/javascript">
+
+window.jsTestIsAsync = true;
+
+description("Showing and populating the tracks panel.");
+
+const media = document.querySelector("video");
+const shadowRoot = window.internals.shadowRoot(media);
+
+media.addEventListener("play", () => {
+    media.pause();
+    window.requestAnimationFrame(() => {
+        clickOnTracksButton();
+        window.requestAnimationFrame(() => {
+            listContentsOfTracksPanel();
+            media.remove();
+            finishJSTest();
+        });
+    });
+});
+
+function clickOnTracksButton()
+{
+    const bounds = shadowRoot.lastChild.querySelector("button.tracks").getBoundingClientRect();
+    eventSender.mouseMoveTo(bounds.left + 1, bounds.top + 1);
+    eventSender.mouseDown();
+    eventSender.mouseUp();
+}
+
+function listContentsOfTracksPanel()
+{
+    for (let section of shadowRoot.lastChild.querySelectorAll(".tracks-panel-section")) {
+        debug(section.querySelector("h3").textContent);
+        for (let item of section.querySelectorAll("li"))
+            debug("  " + item.textContent);
+        debug("");
+    }
+}
+
+</script>
+<script src="../../../resources/js-test-post.js"></script>
+</body>
index e253418..d5d33ab 100644 (file)
@@ -2741,10 +2741,11 @@ webkit.org/b/158836 imported/w3c/web-platform-tests/encrypted-media [ Skip ]
 # Only Mac has implemented DictionaryLookup
 fast/layers/prevent-hit-test-during-layout.html [ Skip ]
 
-# Internal APIs to test PiP and AirPlay are not available on iOS.
+# Internal APIs to test PiP and AirPlay are not available on iOS, and we don't support showing the tracks button on iOS.
 media/modern-media-controls/airplay-support/airplay-support.html [ Skip ]
 media/modern-media-controls/pip-support [ Skip ]
 media/modern-media-controls/placard-support [ Skip ]
+media/modern-media-controls/tracks-support [ Skip ]
 media/modern-media-controls/audio [ Skip ]
 
 # Mac-specific tests for fullscreen.
index 1efe464..a2559fd 100644 (file)
@@ -1453,6 +1453,8 @@ webkit.org/b/164088 [ Yosemite ] media/modern-media-controls/scrubber-support/sc
 [ Yosemite ] media/modern-media-controls/audio [ Skip ]
 [ Yosemite ] media/modern-media-controls/media-controller/media-controller-fullscreen-ltr.html [ Skip ]
 [ Yosemite ] media/modern-media-controls/tracks-panel/tracks-panel-select-track-with-keyboard.html [ Skip ]
+[ Yosemite ] media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html [ Skip ]
+[ Yosemite ] media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html [ Skip ]
 
 webkit.org/b/164616 http/tests/media/modern-media-controls/skip-back-support/skip-back-support-button-click.html [ Pass Failure ]
 webkit.org/b/164323 media/modern-media-controls/airplay-support/airplay-support.html [ Pass Failure ]
index 7a9ef69..5f35ba4 100644 (file)
@@ -1,3 +1,52 @@
+2016-12-01  Antoine Quint  <graouts@apple.com>
+
+        [Modern Media Controls] Show and populate the tracks panel
+        https://bugs.webkit.org/show_bug.cgi?id=165284
+
+        Reviewed by Dean Jackson.
+
+        We added a TracksPanel in https://bugs.webkit.org/show_bug.cgi?id=165239 which allows to
+        show a list of media tracks and text tracks to choose from. We now show this panel when
+        clicking on the tracks button in the controls bar and populate its content with the
+        list of audio and text tracks for the media element. As an item is picked from the tracks
+        panel, we toggle the represented track's enabled state and dismiss the panel.
+
+        We also pick up the text track container display mostly unchanged from current media controls.
+
+        Tests: media/modern-media-controls/tracks-support/tracks-support-click-track-in-panel.html
+               media/modern-media-controls/tracks-support/tracks-support-show-and-populate-panel.html
+
+        * Modules/modern-media-controls/controls/macos-inline-media-controls.js:
+        (MacOSInlineMediaControls.prototype.showTracksPanel):
+        * Modules/modern-media-controls/controls/text-tracks.css: Added.
+        (video::-webkit-media-text-track-container):
+        (video::cue):
+        (video::-webkit-media-text-track-display):
+        (video::-webkit-media-text-track-display-backdrop):
+        (video::cue(:future)):
+        (video::-webkit-media-text-track-container b):
+        (video::-webkit-media-text-track-container u):
+        (video::-webkit-media-text-track-container i):
+        (video::-webkit-media-text-track-container .hidden):
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController):
+        * Modules/modern-media-controls/media/tracks-support.js:
+        (TracksSupport):
+        (TracksSupport.prototype.destroy):
+        (TracksSupport.prototype.buttonWasClicked):
+        (TracksSupport.prototype.tracksPanelNumberOfSections):
+        (TracksSupport.prototype.tracksPanelTitleForSection):
+        (TracksSupport.prototype.tracksPanelNumberOfTracksInSection):
+        (TracksSupport.prototype.tracksPanelTitleForTrackInSection):
+        (TracksSupport.prototype.tracksPanelIsTrackInSectionSelected):
+        (TracksSupport.prototype.tracksPanelSelectionDidChange):
+        (TracksSupport.prototype.syncControl):
+        (TracksSupport.prototype._textTracks):
+        (TracksSupport.prototype._audioTracks):
+        (TracksSupport.prototype._canPickAudioTracks):
+        (TracksSupport.prototype._canPickTextTracks):
+        (TracksSupport.prototype._sortedTrackList):
+
 2016-12-01  Brent Fulgham  <bfulgham@apple.com>
 
         Rare crash when preparing to print
index 286b71f..1ae8059 100644 (file)
@@ -118,6 +118,12 @@ class MacOSInlineMediaControls extends MacOSMediaControls
         this._volumeSliderContainer.x = this._rightContainer.x + this.muteButton.x;
     }
 
+    showTracksPanel()
+    {
+        super.showTracksPanel();
+        this.tracksPanel.rightX = this._rightContainer.width - this.tracksButton.x - this.tracksButton.width;
+    }
+
     // Protected
 
     handleEvent(event)
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/text-tracks.css b/Source/WebCore/Modules/modern-media-controls/controls/text-tracks.css
new file mode 100644 (file)
index 0000000..8c0bf9b
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+video::-webkit-media-text-track-container {
+    position: relative;
+    width: 100%;
+    bottom: 50px;
+    overflow: hidden;
+    padding-bottom: 5px;
+    z-index: 0;
+
+    text-align: center;
+    color: rgba(255, 255, 255, 1);
+
+    letter-spacing: normal;
+    word-spacing: normal;
+    text-transform: none;
+    text-indent: 0;
+    text-decoration: none;
+    pointer-events: none;
+    -webkit-user-select: none;
+
+    -webkit-flex: 1 1 auto;
+
+    -webkit-line-box-contain: block inline-box replaced;
+}
+
+video::cue {
+    background-color: rgba(0, 0, 0, 0.8);
+}
+
+video::-webkit-media-text-track-display {
+    position: absolute;
+    overflow: hidden;
+    white-space: pre-wrap;
+    -webkit-box-sizing: border-box;
+    font: 22px sans-serif;
+}
+
+video::-webkit-media-text-track-display-backdrop {
+    display: inline-block;
+}
+
+video::cue(:future) {
+    color: gray;
+}
+
+video::-webkit-media-text-track-container b {
+    font-weight: bold;
+}
+
+video::-webkit-media-text-track-container u {
+    text-decoration: underline;
+}
+
+video::-webkit-media-text-track-container i {
+    font-style: italic;
+}
+
+video::-webkit-media-text-track-container .hidden {
+    display: none;
+}
index 60d6e0e..9b7ff5b 100644 (file)
@@ -32,8 +32,10 @@ class MediaController
         this.media = media;
         this.host = host;
 
-        if (host)
+        if (host) {
             media.addEventListener("webkitpresentationmodechanged", this);
+            shadowRoot.appendChild(host.textTrackContainer);
+        }
 
         this._updateControlsIfNeeded();
 
index 0fd4e04..8845f09 100644 (file)
@@ -33,9 +33,12 @@ class TracksSupport extends MediaControllerSupport
         if (!this.control)
             return;
 
+        this.mediaController.controls.tracksPanel.dataSource = this;
+        this.mediaController.controls.tracksPanel.uiDelegate = this;
+
         const media = mediaController.media;
         for (let tracks of [media.audioTracks, media.textTracks]) {
-            for (let eventType of ["addtrack", "removetrack"])
+            for (let eventType of ["addtrack", "change", "removetrack"])
                 tracks.addEventListener(eventType, this);
         }
     }
@@ -48,7 +51,7 @@ class TracksSupport extends MediaControllerSupport
 
         const media = this.mediaController.media;
         for (let tracks of [media.audioTracks, media.textTracks]) {
-            for (let eventType of ["addtrack", "removetrack"])
+            for (let eventType of ["addtrack", "change", "removetrack"])
                 tracks.removeEventListener(eventType, this);
         }
     }
@@ -67,18 +70,100 @@ class TracksSupport extends MediaControllerSupport
 
     buttonWasClicked(control)
     {
-        // FIXME: Show tracks menu.
+        this.mediaController.controls.showTracksPanel();
+    }
+
+    tracksPanelNumberOfSections()
+    {
+        let numberOfSections = 0;
+        if (this._canPickAudioTracks())
+            numberOfSections++;
+        if (this._canPickTextTracks())
+            numberOfSections++;
+        return numberOfSections;
+    }
+
+    tracksPanelTitleForSection(sectionIndex)
+    {
+        if (sectionIndex == 0 && this._canPickAudioTracks())
+            return UIString("Audio");
+        return UIString("Subtitles");
+    }
+
+    tracksPanelNumberOfTracksInSection(sectionIndex)
+    {
+        if (sectionIndex == 0 && this._canPickAudioTracks())
+            return this._audioTracks().length;
+        return this._textTracks().length;
+    }
+
+    tracksPanelTitleForTrackInSection(trackIndex, sectionIndex)
+    {
+        let track;
+        if (sectionIndex == 0 && this._canPickAudioTracks())
+            track = this._audioTracks()[trackIndex];
+        else
+            track = this._textTracks()[trackIndex];
+
+        if (this.mediaController.host)
+            return this.mediaController.host.displayNameForTrack(track);
+        return track.label;
+    }
+
+    tracksPanelIsTrackInSectionSelected(trackIndex, sectionIndex)
+    {
+        if (sectionIndex == 0 && this._canPickAudioTracks())
+            return this._audioTracks()[trackIndex].enabled;
+        return this._textTracks()[trackIndex].mode !== "disabled";
+    }
+
+    tracksPanelSelectionDidChange(trackIndex, sectionIndex)
+    {
+        if (sectionIndex == 0 && this._canPickAudioTracks()) {
+            let track = this._audioTracks()[trackIndex];
+            track.enabled = !track.enabled;
+        } else {
+            let track = this._textTracks()[trackIndex];
+            track.mode = track.mode === "disabled" ? "showing" : "disabled";
+        }
+
+        this.mediaController.controls.hideTracksPanel();
     }
 
     syncControl()
     {
-        const media = this.mediaController.media;
-        const host = this.mediaController.host;
+        this.control.enabled = this._canPickAudioTracks() || this._canPickTextTracks();
+    }
+
+    // Private
+
+    _textTracks()
+    {
+        return this._sortedTrackList(this.mediaController.media.textTracks);
+    }
 
-        const textTracks = host ? host.sortedTrackListForMenu(media.textTracks) : media.textTracks;
-        const audioTracks = host ? host.sortedTrackListForMenu(media.audioTracks) : media.audioTracks;
+    _audioTracks()
+    {
+        return this._sortedTrackList(this.mediaController.media.audioTracks);
+    }
+
+    _canPickAudioTracks()
+    {
+        const audioTracks = this._audioTracks();
+        return audioTracks && audioTracks.length > 1;
+    }
 
-        this.control.enabled = (textTracks && textTracks.length > 0) || (audioTracks && audioTracks.length > 1);
+    _canPickTextTracks()
+    {
+        const textTracks = this._textTracks();
+        return textTracks && textTracks.length > 0;
+    }
+
+    _sortedTrackList(tracks)
+    {
+        if (this.mediaController.host)
+            return this.mediaController.host.sortedTrackListForMenu(tracks);
+        return tracks;
     }
 
 }