[Modern Media Controls] Show a loading indicator after pressing the play button in...
authorgraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Apr 2018 21:49:04 +0000 (21:49 +0000)
committergraouts@webkit.org <graouts@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 21 Apr 2018 21:49:04 +0000 (21:49 +0000)
https://bugs.webkit.org/show_bug.cgi?id=184863
<rdar://problem/38939468>

Reviewed by Dean Jackson.

Source/WebCore:

We now display a loading indicator after pressing the play button when in compact mode. We also update the
behavior to use assets provided through WebKitAdditions (see webkit.org/b/184862) for the play button and
the invalid icon. Additionally, we always show a 20% opaque black overlay in the background while any piece
of user interface is up.

* Modules/modern-media-controls/controls/compact-activity-indicator.css: Added.
(button.compact-activity-indicator > picture): The loading indicator asset is a sprite made of 23 frames, so
we specify the mask size (since all buttons are rendered via a mask) to be 23 * 100% the rendered size. The
display of the loading indicator is performed with a first intro animation which runs once through the first
8 frames and then a continuously looping animation going through the remaining frames. We use a frames()
timing function to achieve the frame-by-frame effect while using only from/to keyframe animations. When we
fade out, we use a simply opacity fade, which is combined with the spinning animation. We use CSS variables
to encode both animations so they can be used combined or one at a time without redefining the whole animation
property.
(button.compact-activity-indicator.spins > picture): Use the "spins" animation variable when spinning.
(button.compact-activity-indicator.spins.fades-out > picture): Combine the "spins" and "fades-out" animation
variables when fading out.
(@keyframes compact-activity-indicator-intro): Animation going through the first 8 frames of the loading indicator.
(@keyframes compact-activity-indicator-loop): Animation going through the remaining frames of the loading indicator.
(@keyframes compact-activity-indicator-fades-out): Animation fading opacity from 1 to 0.
* Modules/modern-media-controls/controls/compact-activity-indicator.js: Added.
(CompactActivityIndicator):
(CompactActivityIndicator.prototype.show): Add the "spins" CSS class to show the control spinning with the intro animation.
(CompactActivityIndicator.prototype.hide): Add the "fades-out" CSS class to hide the control, removing both this class and
the "spins" class when the fade-out animation completes.
* Modules/modern-media-controls/controls/compact-media-controls.css: Added.
(.media-controls.compact:before): Add a 20% black overlay over the video frame to provide contrast for controls.
(.media-controls.compact button): Ensure buttons are sized to use the entire video frame so that their hit region
comprises the whole video frame.
(.media-controls.compact button > picture): Override default blending styles for a simple solid white mask.
(.media-controls.compact button:active > picture): Turn off the scale down effect when pressing a button.
* Modules/modern-media-controls/controls/compact-media-controls.js: Expose a "state" property for the compact media controls,
which can be exlusively one of three: "paused", "pending" and "invalid".
(CompactMediaControls.):
(CompactMediaControls.prototype.get state):
(CompactMediaControls.prototype.set state):
(CompactMediaControls.prototype.layout): In the "paused" state, show the play button. In the "pending" state show
the loading indicator. In the "invalid" state show the invalid button.
(CompactMediaControls.prototype.get placard): Deleted.
(CompactMediaControls.prototype.set placard): Deleted.
* Modules/modern-media-controls/js-files:
* Modules/modern-media-controls/media/compact-media-controls-support.js: Added.
(CompactMediaControlsSupport.prototype.get mediaEvents):
(CompactMediaControlsSupport.prototype.handleEvent): Make the controls enter the "paused" state when receiving a "pause"
event. Make the controls enter the "invalid" state when receiving an "error" event.
(CompactMediaControlsSupport.prototype.enable):
(CompactMediaControlsSupport.prototype.disable):
(CompactMediaControlsSupport.prototype.buttonWasPressed): Play the media when pressing the play button and make the controls
enter the "pending" state. When pressing the loading indicator, pause the media and make the controls enter the "paused" state.
(CompactMediaControlsSupport.prototype._buttons):
(CompactMediaControlsSupport):
* Modules/modern-media-controls/media/media-controller.js:
(MediaController.prototype._supportingObjectClasses): Only use CompactMediaControlsSupport as a media controller supporting object
in the compact mode.
* Modules/modern-media-controls/media/placard-support.js:
(PlacardSupport.prototype.get mediaEvents): This media controller support object no longer needs to deal with compact mode.
* Modules/modern-media-controls/media/playback-support.js:
(PlaybackSupport.prototype.syncControl): This media controller support object no longer needs to deal with compact mode.
(PlaybackSupport):

LayoutTests:

* media/modern-media-controls/compact-media-controls/compact-media-controls-constructor-expected.txt:
* media/modern-media-controls/compact-media-controls/compact-media-controls-constructor.html:
* media/modern-media-controls/compact-media-controls/compact-media-controls-layout-expected.txt:
* media/modern-media-controls/compact-media-controls/compact-media-controls-layout.html:

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/media/modern-media-controls/compact-media-controls/compact-media-controls-constructor-expected.txt
LayoutTests/media/modern-media-controls/compact-media-controls/compact-media-controls-constructor.html
LayoutTests/media/modern-media-controls/compact-media-controls/compact-media-controls-layout-expected.txt
LayoutTests/media/modern-media-controls/compact-media-controls/compact-media-controls-layout.html
Source/WebCore/ChangeLog
Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.css [new file with mode: 0644]
Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.js [new file with mode: 0644]
Source/WebCore/Modules/modern-media-controls/controls/compact-media-controls.css [new file with mode: 0644]
Source/WebCore/Modules/modern-media-controls/controls/compact-media-controls.js
Source/WebCore/Modules/modern-media-controls/js-files
Source/WebCore/Modules/modern-media-controls/media/compact-media-controls-support.js [new file with mode: 0644]
Source/WebCore/Modules/modern-media-controls/media/media-controller.js
Source/WebCore/Modules/modern-media-controls/media/placard-support.js
Source/WebCore/Modules/modern-media-controls/media/playback-support.js

index 2e132e5..c0ab201 100644 (file)
@@ -1,3 +1,16 @@
+2018-04-21  Antoine Quint  <graouts@apple.com>
+
+        [Modern Media Controls] Show a loading indicator after pressing the play button in compact mode
+        https://bugs.webkit.org/show_bug.cgi?id=184863
+        <rdar://problem/38939468>
+
+        Reviewed by Dean Jackson.
+
+        * media/modern-media-controls/compact-media-controls/compact-media-controls-constructor-expected.txt:
+        * media/modern-media-controls/compact-media-controls/compact-media-controls-constructor.html:
+        * media/modern-media-controls/compact-media-controls/compact-media-controls-layout-expected.txt:
+        * media/modern-media-controls/compact-media-controls/compact-media-controls-layout.html:
+
 2018-04-21  Youenn Fablet  <youenn@apple.com>
 
         Activate NetworkLoadChecker for media loads
index 25340fc..662ac25 100644 (file)
@@ -1,12 +1,15 @@
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = PlayCompact, layoutTraits = 8, src = PlayCompact.pdf
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = InvalidCompact, layoutTraits = 8, src = InvalidCompact.pdf
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = ActivityIndicatorSpriteCompact, layoutTraits = 8, src = ActivityIndicatorSpriteCompact@1x.png
 Testing the CompactMediaControls constructor.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
 PASS mediaControls.element.localName is "div"
-PASS mediaControls.element.className is "media-controls"
+PASS mediaControls.element.className is "compact media-controls"
 PASS mediaControls.layoutTraits is LayoutTraits.Compact
-PASS mediaControls.placard is null
+PASS mediaControls.state is CompactMediaControls.States.Paused
 
 PASS successfullyParsed is true
 
index 213f221..7ab9add 100644 (file)
@@ -8,9 +8,9 @@ description("Testing the <code>CompactMediaControls</code> constructor.");
 const mediaControls = new CompactMediaControls;
 
 shouldBeEqualToString("mediaControls.element.localName", "div");
-shouldBeEqualToString("mediaControls.element.className", "media-controls");
+shouldBeEqualToString("mediaControls.element.className", "compact media-controls");
 shouldBe("mediaControls.layoutTraits", "LayoutTraits.Compact");
-shouldBeNull("mediaControls.placard");
+shouldBe("mediaControls.state", "CompactMediaControls.States.Paused");
 debug("");
 
 </script>
index 3cade1a..183d1eb 100644 (file)
@@ -1,23 +1,19 @@
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = PlayCompact, layoutTraits = 8, src = PlayCompact.pdf
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = InvalidCompact, layoutTraits = 8, src = InvalidCompact.pdf
+CONSOLE MESSAGE: line 140: Button failed to load, iconName = ActivityIndicatorSpriteCompact, layoutTraits = 8, src = ActivityIndicatorSpriteCompact@1x.png
 Testing the CompactMediaControls layout.
 
 On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
 
 
-With controls at their default size only the play/pause button is showing with a center style.
-PASS mediaControls.children is [mediaControls.playPauseButton]
-PASS mediaControls.playPauseButton.style is Button.Styles.Center
+With controls at their default state (paused) only the play button is showing.
+PASS mediaControls.children is [mediaControls.playButton]
 
-With controls just under the minimum size to show prominent controls only the play/pause button is showing with a small-center style.
-PASS mediaControls.children is [mediaControls.playPauseButton]
-PASS mediaControls.playPauseButton.style is Button.Styles.SmallCenter
+With controls at pending state, only the activity indicator is showing.
+PASS mediaControls.children is [mediaControls.activityIndicator]
 
-With controls just under the minimum size to show any controls there are no children.
-PASS mediaControls.children.length is 0
-
-With controls above the minimum size and the error placard set only the invalid placard is shown.
-PASS mediaControls.children is [mediaControls.invalidPlacard]
-PASS mediaControls.invalidPlacard.width is mediaControls.width
-PASS mediaControls.invalidPlacard.height is mediaControls.height
+With controls at invalid state, only the invalid icon is showing.
+PASS mediaControls.children is [mediaControls.invalidButton]
 
 PASS successfullyParsed is true
 
index 04b5f5a..d3e4689 100644 (file)
@@ -8,31 +8,18 @@ description("Testing the <code>CompactMediaControls</code> layout.");
 
 const mediaControls = new CompactMediaControls;
 
-debug("With controls at their default size only the play/pause button is showing with a center style.");
-shouldBe("mediaControls.children", "[mediaControls.playPauseButton]");
-shouldBe("mediaControls.playPauseButton.style", "Button.Styles.Center");
+debug("With controls at their default state (paused) only the play button is showing.");
+shouldBe("mediaControls.children", "[mediaControls.playButton]");
 debug("");
 
-debug("With controls just under the minimum size to show prominent controls only the play/pause button is showing with a small-center style.");
-mediaControls.width = MaximumSizeToShowSmallProminentControl - 1;
-mediaControls.height = MaximumSizeToShowSmallProminentControl - 1;
-shouldBe("mediaControls.children", "[mediaControls.playPauseButton]");
-shouldBe("mediaControls.playPauseButton.style", "Button.Styles.SmallCenter");
+mediaControls.state = CompactMediaControls.States.Pending;
+debug("With controls at pending state, only the activity indicator is showing.");
+shouldBe("mediaControls.children", "[mediaControls.activityIndicator]");
 debug("");
 
-debug("With controls just under the minimum size to show any controls there are no children.");
-mediaControls.width = MinimumSizeToShowAnyControl - 1;
-mediaControls.height = MinimumSizeToShowAnyControl - 1;
-shouldBe("mediaControls.children.length", "0");
-debug("");
-
-debug("With controls above the minimum size and the error placard set only the invalid placard is shown.");
-mediaControls.width = MaximumSizeToShowSmallProminentControl;
-mediaControls.height = MaximumSizeToShowSmallProminentControl;
-mediaControls.placard = mediaControls.invalidPlacard;
-shouldBe("mediaControls.children", "[mediaControls.invalidPlacard]");
-shouldBe("mediaControls.invalidPlacard.width", "mediaControls.width");
-shouldBe("mediaControls.invalidPlacard.height", "mediaControls.height");
+mediaControls.state = CompactMediaControls.States.Invalid;
+debug("With controls at invalid state, only the invalid icon is showing.");
+shouldBe("mediaControls.children", "[mediaControls.invalidButton]");
 debug("");
 
 </script>
index ec97915..fda1d9b 100644 (file)
@@ -1,5 +1,73 @@
 2018-04-21  Antoine Quint  <graouts@apple.com>
 
+        [Modern Media Controls] Show a loading indicator after pressing the play button in compact mode
+        https://bugs.webkit.org/show_bug.cgi?id=184863
+        <rdar://problem/38939468>
+
+        Reviewed by Dean Jackson.
+
+        We now display a loading indicator after pressing the play button when in compact mode. We also update the
+        behavior to use assets provided through WebKitAdditions (see webkit.org/b/184862) for the play button and
+        the invalid icon. Additionally, we always show a 20% opaque black overlay in the background while any piece
+        of user interface is up.
+
+        * Modules/modern-media-controls/controls/compact-activity-indicator.css: Added.
+        (button.compact-activity-indicator > picture): The loading indicator asset is a sprite made of 23 frames, so
+        we specify the mask size (since all buttons are rendered via a mask) to be 23 * 100% the rendered size. The
+        display of the loading indicator is performed with a first intro animation which runs once through the first
+        8 frames and then a continuously looping animation going through the remaining frames. We use a frames()
+        timing function to achieve the frame-by-frame effect while using only from/to keyframe animations. When we
+        fade out, we use a simply opacity fade, which is combined with the spinning animation. We use CSS variables
+        to encode both animations so they can be used combined or one at a time without redefining the whole animation
+        property.
+        (button.compact-activity-indicator.spins > picture): Use the "spins" animation variable when spinning.
+        (button.compact-activity-indicator.spins.fades-out > picture): Combine the "spins" and "fades-out" animation
+        variables when fading out.
+        (@keyframes compact-activity-indicator-intro): Animation going through the first 8 frames of the loading indicator.
+        (@keyframes compact-activity-indicator-loop): Animation going through the remaining frames of the loading indicator.
+        (@keyframes compact-activity-indicator-fades-out): Animation fading opacity from 1 to 0.
+        * Modules/modern-media-controls/controls/compact-activity-indicator.js: Added.
+        (CompactActivityIndicator):
+        (CompactActivityIndicator.prototype.show): Add the "spins" CSS class to show the control spinning with the intro animation.
+        (CompactActivityIndicator.prototype.hide): Add the "fades-out" CSS class to hide the control, removing both this class and
+        the "spins" class when the fade-out animation completes.
+        * Modules/modern-media-controls/controls/compact-media-controls.css: Added.
+        (.media-controls.compact:before): Add a 20% black overlay over the video frame to provide contrast for controls.
+        (.media-controls.compact button): Ensure buttons are sized to use the entire video frame so that their hit region
+        comprises the whole video frame.
+        (.media-controls.compact button > picture): Override default blending styles for a simple solid white mask.
+        (.media-controls.compact button:active > picture): Turn off the scale down effect when pressing a button.
+        * Modules/modern-media-controls/controls/compact-media-controls.js: Expose a "state" property for the compact media controls,
+        which can be exlusively one of three: "paused", "pending" and "invalid".
+        (CompactMediaControls.):
+        (CompactMediaControls.prototype.get state):
+        (CompactMediaControls.prototype.set state):
+        (CompactMediaControls.prototype.layout): In the "paused" state, show the play button. In the "pending" state show
+        the loading indicator. In the "invalid" state show the invalid button.
+        (CompactMediaControls.prototype.get placard): Deleted.
+        (CompactMediaControls.prototype.set placard): Deleted.
+        * Modules/modern-media-controls/js-files:
+        * Modules/modern-media-controls/media/compact-media-controls-support.js: Added.
+        (CompactMediaControlsSupport.prototype.get mediaEvents):
+        (CompactMediaControlsSupport.prototype.handleEvent): Make the controls enter the "paused" state when receiving a "pause"
+        event. Make the controls enter the "invalid" state when receiving an "error" event. 
+        (CompactMediaControlsSupport.prototype.enable):
+        (CompactMediaControlsSupport.prototype.disable):
+        (CompactMediaControlsSupport.prototype.buttonWasPressed): Play the media when pressing the play button and make the controls
+        enter the "pending" state. When pressing the loading indicator, pause the media and make the controls enter the "paused" state.
+        (CompactMediaControlsSupport.prototype._buttons):
+        (CompactMediaControlsSupport):
+        * Modules/modern-media-controls/media/media-controller.js:
+        (MediaController.prototype._supportingObjectClasses): Only use CompactMediaControlsSupport as a media controller supporting object
+        in the compact mode.
+        * Modules/modern-media-controls/media/placard-support.js:
+        (PlacardSupport.prototype.get mediaEvents): This media controller support object no longer needs to deal with compact mode.
+        * Modules/modern-media-controls/media/playback-support.js:
+        (PlaybackSupport.prototype.syncControl): This media controller support object no longer needs to deal with compact mode.
+        (PlaybackSupport):
+
+2018-04-21  Antoine Quint  <graouts@apple.com>
+
         [Modern Media Controls] Obtain compact mode icons through WebKitAdditions
         https://bugs.webkit.org/show_bug.cgi?id=184862
         <rdar://problem/39621645>
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.css b/Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.css
new file mode 100644 (file)
index 0000000..f03d862
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+button.compact-activity-indicator > picture {
+    --width: 27px;
+
+    /* There are 23 frames in the sprite. */
+    --number-of-frames: 23;
+
+    width: var(--width) !important;
+    height: 29.5px !important;
+    
+    -webkit-mask-size: calc(var(--number-of-frames) * 100%) 100%;
+
+    /* We apply two animations in sequence, first the intro which goes for 8 frames (0 - 7) and whichs
+       runs once, then the loop which starts after the intro (using a delay) and runs infinitely. */
+    --spins: compact-activity-indicator-intro frames(8) calc(8s / 15), compact-activity-indicator-loop frames(15) 1s calc(8s / 15) infinite;
+
+    /* When we fade out. */
+    --fades-out: compact-activity-indicator-fades-out 500ms;
+}
+
+button.compact-activity-indicator.spins > picture {
+    animation: var(--spins);
+}
+
+button.compact-activity-indicator.spins.fades-out > picture {
+    animation: var(--spins), var(--fades-out);
+}
+
+/* This is the intro animation that runs once only and goes through the first 8 frames of the sprite. */
+@keyframes compact-activity-indicator-intro {
+    from { -webkit-mask-position-x: 0 }
+    to   { -webkit-mask-position-x: calc(-7 * var(--width)) }
+}
+
+/* This is the main animation that runs infinitely once the intro has completed and goes through the frames 9 through 23 of the sprite. */
+@keyframes compact-activity-indicator-loop {
+    from { -webkit-mask-position-x: calc(-8 * var(--width)) }
+    to   { -webkit-mask-position-x: calc(-22 * var(--width)) }
+}
+
+@keyframes compact-activity-indicator-fades-out {
+    from { opacity: 1 }
+    to   { opacity: 0 }
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.js b/Source/WebCore/Modules/modern-media-controls/controls/compact-activity-indicator.js
new file mode 100644 (file)
index 0000000..f3c00ee
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+class CompactActivityIndicator extends Button
+{
+
+    constructor(layoutDelegate)
+    {
+        super({
+            cssClassName: "compact-activity-indicator",
+            iconName: Icons.SpinnerCompact,
+            layoutDelegate
+        });
+    }
+
+    // Public
+
+    show()
+    {
+        const classList = this.element.classList;
+        classList.add("spins");
+        classList.remove("fades-out");
+    }
+
+    hide()
+    {
+        const classList = this.element.classList;
+        if (!classList.contains("spins") || classList.contains("fades-out"))
+            return;
+
+        classList.add("fades-out");
+        this.image.element.addEventListener("animationend", event => {
+            if (event.animationName !== "compact-activity-indicator-fades-out")
+                return;
+            classList.remove("spins");
+            classList.remove("fades-out");
+        }, { once: true });
+    }
+    
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/compact-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/compact-media-controls.css
new file mode 100644 (file)
index 0000000..a1d83bf
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+.media-controls.compact:before {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100%;
+    height: 100%;
+    background-color: rgba(0, 0, 0, 0.2);
+    content: "";    
+}
+
+.media-controls.compact button {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 100% !important;
+    height: 100% !important;
+}
+
+.media-controls.compact button > picture {
+    /* Override default button behavior. */
+    mix-blend-mode: normal;
+    background-color: white;
+    transition-duration: 0;
+}
+
+.media-controls.compact button:active > picture {
+    /* Override default button behavior. */
+    transform: none;
+}
index 74bc0ab..ab2851f 100644 (file)
@@ -28,17 +28,27 @@ class CompactMediaControls extends LayoutNode
 
     constructor({ width = 320, height = 240 } = {})
     {
-        super(`<div class="media-controls"></div>`);
+        super(`<div class="compact media-controls"></div>`);
 
+        this._state = CompactMediaControls.States.Paused;
         this._scaleFactor = 1;
         this._shouldCenterControlsVertically = false;
 
         this.layoutTraits = LayoutTraits.Compact;
 
-        this.playPauseButton = new PlayPauseButton(this);
-        this.invalidPlacard = new InvalidPlacard(this);
+        this.playButton = new Button({
+            cssClassName: "play",
+            iconName: Icons.PlayCompact,
+            layoutDelegate: this
+        });
 
-        this._placard = null;
+        this.invalidButton = new Button({
+            cssClassName: "invalid",
+            iconName: Icons.InvalidCompact,
+            layoutDelegate: this
+        });
+
+        this.activityIndicator = new CompactActivityIndicator(this);
 
         this.width = width;
         this.height = height;
@@ -74,17 +84,17 @@ class CompactMediaControls extends LayoutNode
         this.markDirtyProperty("scaleFactor");
     }
 
-    get placard()
+    get state()
     {
-        return this._placard;
+        return this._state;
     }
 
-    set placard(placard)
+    set state(state)
     {
-        if (this._placard === placard)
+        if (this._state === state)
             return;
 
-        this._placard = placard;
+        this._state = state;
         this.layout();
     }
 
@@ -94,28 +104,18 @@ class CompactMediaControls extends LayoutNode
     {
         super.layout();
 
-        const children = [];
-
-        // The controls might be too small to allow showing anything at all.
-        if (this.width < MinimumSizeToShowAnyControl || this.height < MinimumSizeToShowAnyControl) {
-            this.children = children;
-            return;
-        }
-
-        // If we are showing the invalid placard, show the placard only.
-        if (this._placard === this.invalidPlacard) {
-            this._placard.width = this.width;
-            this._placard.height = this.height;
-            this.children = [this._placard];
-            return;
-        }
-
-        if (this.playPauseButton.visible) {
-            this.playPauseButton.style = this.width <= MaximumSizeToShowSmallProminentControl || this.height <= MaximumSizeToShowSmallProminentControl ? Button.Styles.SmallCenter : Button.Styles.Center;
-            children.push(this.playPauseButton);
+        switch (this._state) {
+        case CompactMediaControls.States.Paused:
+            this.children = [this.playButton];
+            break;
+        case CompactMediaControls.States.Pending:
+            this.children = [this.activityIndicator];
+            this.activityIndicator.show();
+            break;
+        case CompactMediaControls.States.Invalid:
+            this.children = [this.invalidButton];
+            break;
         }
-
-        this.children = children;
     }
 
     commitProperty(propertyName)
@@ -143,3 +143,9 @@ class CompactMediaControls extends LayoutNode
     }
 
 }
+
+CompactMediaControls.States = {
+    Paused: "paused",
+    Pending: "pending",
+    Invalid: "invalid"
+};
index 2e0b47a..997fceb 100644 (file)
@@ -39,6 +39,7 @@ controls/placard.js
 controls/airplay-placard.js
 controls/invalid-placard.js
 controls/pip-placard.js
+controls/compact-activity-indicator.js
 controls/compact-media-controls.js
 media/media-controller-support.js
 media/airplay-support.js
@@ -63,4 +64,5 @@ media/volume-down-support.js
 media/volume-support.js
 media/volume-up-support.js
 media/media-document-controller.js
+media/compact-media-controls-support.js
 media/media-controller.js
diff --git a/Source/WebCore/Modules/modern-media-controls/media/compact-media-controls-support.js b/Source/WebCore/Modules/modern-media-controls/media/compact-media-controls-support.js
new file mode 100644 (file)
index 0000000..9abf0cc
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+class CompactMediaControlsSupport extends MediaControllerSupport
+{
+
+    // Protected
+
+    get mediaEvents()
+    {
+        return ["pause", "error"];
+    }
+
+    handleEvent(event)
+    {
+        switch (event.type) {
+        case "pause":
+            this.mediaController.controls.state = CompactMediaControls.States.Paused;
+            break;
+        case "error":
+            this.mediaController.controls.state = CompactMediaControls.States.Invalid;
+            break;
+        }
+    }
+
+    enable()
+    {
+        super.enable();
+        
+        for (let button of this._buttons())
+            button.uiDelegate = this;
+    }
+
+    disable()
+    {
+        super.disable();
+        
+        for (let button of this._buttons())
+            button.uiDelegate = null;
+    }
+
+    buttonWasPressed(button)
+    {
+        if (button === this.mediaController.controls.playButton) {
+            this.mediaController.media.play();
+            this.mediaController.controls.state = CompactMediaControls.States.Pending;
+        } else if (button === this.mediaController.controls.activityIndicator) {
+            this.mediaController.media.pause();
+            this.mediaController.controls.state = CompactMediaControls.States.Paused;
+        }
+    }
+
+    // Private
+
+    _buttons()
+    {
+        return [this.mediaController.controls.playButton, this.mediaController.controls.activityIndicator];
+    }
+
+}
index 27f5b3c..18fa91e 100644 (file)
@@ -186,7 +186,7 @@ class MediaController
     _supportingObjectClasses()
     {
         if (this.layoutTraits & LayoutTraits.Compact)
-            return [PlacardSupport, PlaybackSupport];
+            return [CompactMediaControlsSupport];
 
         return [AirplaySupport, AudioSupport, ControlsVisibilitySupport, FullscreenSupport, MuteSupport, PiPSupport, PlacardSupport, PlaybackSupport, ScrubbingSupport, SeekBackwardSupport, SeekForwardSupport, SkipBackSupport, SkipForwardSupport, StartSupport, StatusSupport, TimeControlSupport, TracksSupport, VolumeSupport, VolumeDownSupport, VolumeUpSupport];
     }
index 1f683de..2bc4d23 100644 (file)
@@ -36,9 +36,6 @@ class PlacardSupport extends MediaControllerSupport
 
     get mediaEvents()
     {
-        if (this.mediaController.layoutTraits & LayoutTraits.Compact)
-            return ["error"];
-
         return ["loadstart", "error", "webkitpresentationmodechanged", "webkitcurrentplaybacktargetiswirelesschanged"];
     }
 
index e501855..9e27e43 100644 (file)
@@ -45,13 +45,7 @@ class PlaybackSupport extends MediaControllerSupport
 
     syncControl()
     {
-        const isPaused = this.mediaController.media.paused;
-
-        // We always show the play button with compact layout.
-        if (this.mediaController.layoutTraits & LayoutTraits.Compact)
-            this.control.visible = true;
-        else
-            this.control.playing = !isPaused;
+        this.control.playing = !this.mediaController.media.paused;
     }
 
 }