summaryrefslogtreecommitdiff
path: root/Source/WebCore/Modules/modern-media-controls/controls
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/Modules/modern-media-controls/controls')
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/airplay-button.css29
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/airplay-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/airplay-placard.js39
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/background-tint.css48
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/background-tint.js34
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/button.css34
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/button.js83
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css29
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js78
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/controls-bar.css35
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/controls-bar.js248
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/forward-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/fullscreen-button.js39
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/icon-button.css33
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/icon-button.js134
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/icon-service.js102
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/invalid-placard.js37
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css132
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.js109
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/layout-item.js53
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/layout-node.js307
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-compact-inline-media-controls.css71
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css119
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.js173
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css118
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.js202
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css51
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js81
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/media-controls.css77
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/media-controls.js148
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/mute-button.js53
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/pip-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/pip-placard.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/placard.css70
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/placard.js48
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/play-pause-button.js53
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/rewind-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/scheduler.js66
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/scrubber.js156
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/seek-button.js73
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/skip-back-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/slider.css47
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/slider.js152
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/start-button.css58
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/start-button.js42
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/status-label.css37
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/status-label.js85
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/text-tracks.css82
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/time-control.js93
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/time-label.css33
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/time-label.js80
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/tracks-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css105
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js305
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/volume-down-button.js38
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/volume-slider.css30
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/volume-slider.js120
-rw-r--r--Source/WebCore/Modules/modern-media-controls/controls/volume-up-button.js38
58 files changed, 4773 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.css b/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.css
new file mode 100644
index 000000000..3856c8db6
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.css
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+button.airplay.on {
+ background-color: -apple-wireless-playback-target-active !important;
+ mix-blend-mode: normal !important;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.js b/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.js
new file mode 100644
index 000000000..3b6c9ed30
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/airplay-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class AirplayButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "airplay",
+ iconName: Icons.Airplay,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/airplay-placard.js b/Source/WebCore/Modules/modern-media-controls/controls/airplay-placard.js
new file mode 100644
index 000000000..f167f48e7
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/airplay-placard.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+class AirplayPlacard extends Placard
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ iconName: Icons.AirplayPlacard,
+ title: UIString("AirPlay"),
+ description: UIString("This video is playing on your Apple TV"),
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/background-tint.css b/Source/WebCore/Modules/modern-media-controls/controls/background-tint.css
new file mode 100644
index 000000000..7de98049f
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/background-tint.css
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+.background-tint {
+ pointer-events: none;
+}
+
+.background-tint,
+.background-tint > div {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.background-tint > .blur {
+ /* FIXME: we want to use the real System Dark treatment here, see <rdar://problem/19993961> */
+ background-color: rgba(30, 30, 30, 0.45);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+}
+
+.background-tint > .tint {
+ background-color: rgb(41, 41, 41);
+ mix-blend-mode: lighten;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/background-tint.js b/Source/WebCore/Modules/modern-media-controls/controls/background-tint.js
new file mode 100644
index 000000000..29df8eeb7
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/background-tint.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2017 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 BackgroundTint extends LayoutNode
+{
+
+ constructor()
+ {
+ super(`<div class="background-tint"><div class="blur"></div><div class="tint"></div></div>`);
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/button.css b/Source/WebCore/Modules/modern-media-controls/controls/button.css
new file mode 100644
index 000000000..bf16ceff2
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/button.css
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+button {
+ position: absolute;
+ top: 0;
+ left: 0;
+ border: 0;
+ -webkit-appearance: none;
+ -webkit-user-select: none;
+ -webkit-tap-highlight-color: transparent;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/button.js b/Source/WebCore/Modules/modern-media-controls/controls/button.js
new file mode 100644
index 000000000..6df091699
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/button.js
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+class Button extends LayoutItem
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ element: "<button />",
+ layoutDelegate
+ });
+
+ this._enabled = true;
+
+ if (GestureRecognizer.SupportsTouches)
+ this._tapGestureRecognizer = new TapGestureRecognizer(this.element, this);
+ else
+ this.element.addEventListener("click", this);
+ }
+
+ // Public
+
+ get enabled()
+ {
+ return this._enabled;
+ }
+
+ set enabled(flag)
+ {
+ if (this._enabled === flag)
+ return;
+
+ this._enabled = flag;
+ if (this.layoutDelegate && typeof this.layoutDelegate.layout === "function")
+ this.layoutDelegate.layout();
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ if (event.type === "click" && event.currentTarget === this.element)
+ this._notifyDelegateOfActivation();
+ }
+
+ gestureRecognizerStateDidChange(recognizer)
+ {
+ if (this._tapGestureRecognizer === recognizer && recognizer.state === GestureRecognizer.States.Recognized)
+ this._notifyDelegateOfActivation();
+ }
+
+ // Private
+
+ _notifyDelegateOfActivation()
+ {
+ if (this._enabled && this.uiDelegate && typeof this.uiDelegate.buttonWasPressed === "function")
+ this.uiDelegate.buttonWasPressed(this);
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css b/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css
new file mode 100644
index 000000000..23469b8f3
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.css
@@ -0,0 +1,29 @@
+/*
+ * 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.
+ */
+
+.buttons-container {
+ position: absolute;
+ height: 100%;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js b/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js
new file mode 100644
index 000000000..0af2602ef
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/buttons-container.js
@@ -0,0 +1,78 @@
+/*
+ * 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.
+ */
+
+class ButtonsContainer extends LayoutNode
+{
+
+ constructor({ buttons = [], leftMargin = 24, rightMargin = 24, buttonMargin = 24, cssClassName = "" } = {})
+ {
+ super(`<div class="buttons-container ${cssClassName}"></div>`);
+
+ this.buttons = buttons;
+ this.leftMargin = leftMargin;
+ this.rightMargin = rightMargin;
+ this.buttonMargin = buttonMargin;
+ }
+
+ // Public
+
+ get buttons()
+ {
+ return this._buttons;
+ }
+
+ set buttons(buttons)
+ {
+ if (!Array.isArray(buttons))
+ return;
+
+ this._buttons = buttons;
+ this.needsLayout = true;
+ }
+
+ layout()
+ {
+ super.layout();
+
+ const children = [];
+ let x = this.leftMargin;
+
+ this._buttons.forEach(button => {
+ if (!button.enabled || button.dropped)
+ return;
+ button.x = x;
+ x += button.width + this.buttonMargin;
+ children.push(button);
+ });
+
+ if (children.length)
+ this.width = x - this.buttonMargin + this.rightMargin;
+ else
+ this.width = this.buttonMargin + this.rightMargin;
+
+ this.children = children;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.css b/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.css
new file mode 100644
index 000000000..e72aea9cc
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.css
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+.controls-bar {
+ position: absolute;
+ transition: opacity 0.1s linear;
+}
+
+.controls-bar.faded {
+ opacity: 0;
+ pointer-events: none;
+ transition-duration: 0.25s;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.js b/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.js
new file mode 100644
index 000000000..25146b833
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/controls-bar.js
@@ -0,0 +1,248 @@
+/*
+ * 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.
+ */
+
+class ControlsBar extends LayoutNode
+{
+
+ constructor(mediaControls)
+ {
+ super(`<div class="controls-bar"></div>`);
+
+ this._translation = new DOMPoint;
+ this._mediaControls = mediaControls;
+
+ if (GestureRecognizer.SupportsTouches)
+ this._tapGestureRecognizer = new TapGestureRecognizer(this._mediaControls.element, this);
+
+ this.autoHideDelay = ControlsBar.DefaultAutoHideDelay;
+
+ this.fadesWhileIdle = false;
+ this.userInteractionEnabled = true;
+ }
+
+ // Public
+
+ get translation()
+ {
+ return new DOMPoint(this._translation.x, this._translation.y);
+ }
+
+ set translation(point)
+ {
+ if (this._translation.x === point.x && this._translation.y === point.y)
+ return;
+
+ this._translation = new DOMPoint(point.x, point.y);
+ this.markDirtyProperty("translation");
+ }
+
+ get userInteractionEnabled()
+ {
+ return this._userInteractionEnabled;
+ }
+
+ set userInteractionEnabled(flag)
+ {
+ if (this._userInteractionEnabled === flag)
+ return;
+
+ this._userInteractionEnabled = flag;
+ this.markDirtyProperty("userInteractionEnabled");
+ }
+
+ get fadesWhileIdle()
+ {
+ return this._fadesWhileIdle;
+ }
+
+ set fadesWhileIdle(flag)
+ {
+ if (this._fadesWhileIdle == flag)
+ return;
+
+ this._fadesWhileIdle = flag;
+
+ if (GestureRecognizer.SupportsTouches)
+ this._tapGestureRecognizer.enabled = flag;
+ else {
+ if (flag) {
+ this._mediaControls.element.addEventListener("mousemove", this);
+ this._mediaControls.element.addEventListener("mouseleave", this);
+ this.element.addEventListener("mouseenter", this);
+ this.element.addEventListener("mouseleave", this);
+ } else {
+ this._mediaControls.element.removeEventListener("mousemove", this);
+ this._mediaControls.element.removeEventListener("mouseleave", this);
+ this.element.removeEventListener("mouseenter", this);
+ this.element.removeEventListener("mouseleave", this);
+ }
+ }
+
+ if (flag && !this.faded)
+ this._resetAutoHideTimer(false);
+ else if (!flag)
+ this.faded = false;
+ }
+
+ get visible()
+ {
+ return super.visible;
+ }
+
+ set visible(flag)
+ {
+ if (this.visible === flag)
+ return;
+
+ // If we just got made visible again, let's fade the controls in.
+ if (flag && !this.visible)
+ this.faded = false;
+ else if (!flag)
+ this._cancelNonEnforcedAutoHideTimer();
+
+ super.visible = flag;
+
+ this._mediaControls.controlsBarVisibilityDidChange(this);
+ }
+
+ get faded()
+ {
+ return !!this._faded;
+ }
+
+ set faded(flag)
+ {
+ if (this._faded === flag)
+ return;
+
+ this._faded = flag;
+ if (!flag)
+ this._resetAutoHideTimer(true);
+ else
+ delete this._enforceAutoHideTimer;
+
+ this.markDirtyProperty("faded");
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ if (event.currentTarget === this._mediaControls.element) {
+ if (event.type === "mousemove") {
+ this.faded = false;
+ this._resetAutoHideTimer(true);
+ } else if (event.type === "mouseleave" && this._fadesWhileIdle && !this._enforceAutoHideTimer)
+ this.faded = true;
+ } else if (event.currentTarget === this.element) {
+ if (event.type === "mouseenter") {
+ this._disableAutoHiding = true;
+ this._cancelNonEnforcedAutoHideTimer();
+ } else if (event.type === "mouseleave") {
+ delete this._disableAutoHiding;
+ this._resetAutoHideTimer(true);
+ } else if (event.type === "focus")
+ this.faded = false;
+ }
+ }
+
+ gestureRecognizerStateDidChange(recognizer)
+ {
+ if (this._tapGestureRecognizer !== recognizer || recognizer.state !== GestureRecognizer.States.Recognized)
+ return;
+
+ if (this.faded)
+ this.faded = false;
+ else {
+ let ancestor = this.element.parentNode;
+ while (ancestor && !(ancestor instanceof ShadowRoot))
+ ancestor = ancestor.parentNode;
+
+ const shadowRoot = ancestor;
+ if (!shadowRoot)
+ return;
+
+ const tapLocation = recognizer.locationInClient();
+ const tappedElement = shadowRoot.elementFromPoint(tapLocation.x, tapLocation.y);
+ if (!this.element.contains(tappedElement))
+ this.faded = true;
+ }
+ }
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "translation")
+ this.element.style.transform = `translate(${this._translation.x}px, ${this._translation.y}px)`;
+ else if (propertyName === "faded")
+ this.element.classList.toggle("faded", this.faded);
+ else if (propertyName === "userInteractionEnabled")
+ this.element.style.pointerEvents = this._userInteractionEnabled ? "all" : "none";
+ else
+ super.commitProperty(propertyName);
+ }
+
+ // Private
+
+ _cancelNonEnforcedAutoHideTimer()
+ {
+ if (!this._enforceAutoHideTimer)
+ this._cancelAutoHideTimer();
+
+ }
+
+ _cancelAutoHideTimer()
+ {
+ window.clearTimeout(this._autoHideTimer);
+ delete this._autoHideTimer;
+ }
+
+ _resetAutoHideTimer(cancelable)
+ {
+ if (cancelable && this._enforceAutoHideTimer)
+ return;
+
+ this._cancelAutoHideTimer();
+
+ if (cancelable)
+ delete this._enforceAutoHideTimer;
+ else
+ this._enforceAutoHideTimer = true;
+
+ this._autoHideTimer = window.setTimeout(this._autoHideTimerFired.bind(this), this.autoHideDelay);
+ }
+
+ _autoHideTimerFired()
+ {
+ delete this._enforceAutoHideTimer;
+ if (this._disableAutoHiding)
+ return;
+
+ this._cancelAutoHideTimer();
+ this.faded = this._fadesWhileIdle;
+ }
+
+}
+
+ControlsBar.DefaultAutoHideDelay = 4000;
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/forward-button.js b/Source/WebCore/Modules/modern-media-controls/controls/forward-button.js
new file mode 100644
index 000000000..5a21221d2
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/forward-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class ForwardButton extends SeekButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "forward",
+ iconName: Icons.Forward,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/fullscreen-button.js b/Source/WebCore/Modules/modern-media-controls/controls/fullscreen-button.js
new file mode 100644
index 000000000..9c7bfd792
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/fullscreen-button.js
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+
+class FullscreenButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "fullscreen",
+ layoutDelegate
+ });
+
+ this.iconName = this.layoutTraits & LayoutTraits.Fullscreen ? Icons.ExitFullscreen : Icons.EnterFullscreen;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/icon-button.css b/Source/WebCore/Modules/modern-media-controls/controls/icon-button.css
new file mode 100644
index 000000000..465f5d367
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/icon-button.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+button.icon {
+ -webkit-mask-repeat: no-repeat;
+}
+
+button.icon:active,
+button.icon.on {
+ background-color: white !important;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js b/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js
new file mode 100644
index 000000000..53e8c3b73
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/icon-button.js
@@ -0,0 +1,134 @@
+/*
+ * 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.
+ */
+
+class IconButton extends Button
+{
+
+ constructor({ layoutDelegate = null, cssClassName = "", iconName = "" } = {})
+ {
+ super(layoutDelegate);
+
+ this.element.classList.add("icon");
+ if (!!cssClassName)
+ this.element.classList.add(cssClassName);
+
+ this._image = null;
+ this._iconName = "";
+ this._iconLayoutTraits = LayoutTraits.Unknown;
+
+ if (!!iconName)
+ this.iconName = iconName;
+ }
+
+ // Public
+
+ get iconName()
+ {
+ return this._iconName;
+ }
+
+ set iconName(iconName)
+ {
+ if (this._iconName === iconName)
+ return;
+
+ this._loadImage(iconName);
+ }
+
+ get on()
+ {
+ return this.element.classList.contains("on");
+ }
+
+ set on(flag) {
+ this.element.classList.toggle("on", flag);
+ }
+
+ layoutTraitsDidChange()
+ {
+ if (this._iconLayoutTraits !== this.layoutTraits)
+ this._loadImage(this._iconName);
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ if (event.type === "load" && event.target === this._image)
+ this._imageDidLoad();
+ else
+ super.handleEvent(event);
+ }
+
+ layout()
+ {
+ super.layout();
+
+ this.element.style.webkitMaskImage = `url(${this._image.src})`;
+ this.element.style.webkitMaskSize = `${this.width}px ${this.height}px`;
+ }
+
+ // Private
+
+ _loadImage(iconName)
+ {
+ if (this._image)
+ this._image.removeEventListener("load", this);
+
+ this._iconLayoutTraits = this.layoutTraits;
+ this._image = iconService.imageForIconNameAndLayoutTraits(iconName, this._iconLayoutTraits);
+
+ this._iconName = iconName;
+
+ if (this._image.complete)
+ this._updateImage();
+ else
+ this._image.addEventListener("load", this);
+ }
+
+ _imageDidLoad()
+ {
+ this._image.removeEventListener("load", this);
+ this._updateImage();
+ }
+
+ _updateImage()
+ {
+ this.needsLayout = true;
+
+ const width = this._image.width / window.devicePixelRatio;
+ const height = this._image.height / window.devicePixelRatio;
+
+ if (this.width === width && this.height === height)
+ return;
+
+ this.width = width;
+ this.height = height;
+
+ if (this.layoutDelegate)
+ this.layoutDelegate.needsLayout = true;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/icon-service.js b/Source/WebCore/Modules/modern-media-controls/controls/icon-service.js
new file mode 100644
index 000000000..417e9f51d
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/icon-service.js
@@ -0,0 +1,102 @@
+/*
+ * 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.
+ */
+
+const Icons = {
+ Airplay : "airplay",
+ AirplayPlacard : "airplay-placard",
+ EnterFullscreen : "enter-fullscreen",
+ EnterPiP : "pip-in",
+ ExitFullscreen : "exit-fullscreen",
+ Forward : "forward",
+ InvalidPlacard : "invalid-placard",
+ Pause : "pause",
+ PiPPlacard : "pip-placard",
+ Play : "play",
+ Rewind : "rewind",
+ ScaleToFill : "scale-to-fill",
+ ScaleToFit : "scale-to-fit",
+ SkipBack : "interval-skip-back",
+ Start : "start",
+ Tracks : "media-selection",
+ Volume : "volume",
+ VolumeDown : "volume-down",
+ VolumeMuted : "volume-mute",
+ VolumeUp : "volume-up"
+};
+
+const IconsWithFullscreenVariants = [Icons.Airplay, Icons.Tracks, Icons.Pause, Icons.EnterPiP, Icons.Play, Icons.VolumeDown, Icons.VolumeUp];
+const IconsWithCompactVariants = [Icons.Play, Icons.Pause, Icons.SkipBack, Icons.Volume, Icons.VolumeMuted, Icons.EnterFullscreen];
+
+const iconService = new class IconService {
+
+ constructor()
+ {
+ this.images = {};
+ }
+
+ // Public
+
+ imageForIconNameAndLayoutTraits(iconName, layoutTraits)
+ {
+ const [fileName, platform] = this._fileNameAndPlatformForIconNameAndLayoutTraits(iconName, layoutTraits);
+ const path = `${platform}/${fileName}.png`;
+
+ let image = this.images[path];
+ if (image)
+ return image;
+
+ image = this.images[path] = new Image;
+
+ if (this.mediaControlsHost)
+ image.src = "data:image/png;base64," + this.mediaControlsHost.base64StringForIconAndPlatform(fileName, platform);
+ else
+ image.src = `${this.directoryPath}/${path}`;
+
+ return image;
+ }
+
+ // Private
+
+ _fileNameAndPlatformForIconNameAndLayoutTraits(iconName, layoutTraits)
+ {
+ let platform;
+ if (layoutTraits & LayoutTraits.macOS)
+ platform = "macOS";
+ else if (layoutTraits & LayoutTraits.iOS)
+ platform = "iOS";
+ else
+ throw "Could not identify icon's platform from layout traits.";
+
+ if (layoutTraits & LayoutTraits.Fullscreen && IconsWithFullscreenVariants.includes(iconName))
+ iconName += "-fullscreen";
+ else if (layoutTraits & LayoutTraits.Compact && IconsWithCompactVariants.includes(iconName))
+ iconName += "-compact";
+
+ const fileName = `${iconName}@${window.devicePixelRatio}x`;
+
+ return [fileName, platform];
+ }
+
+};
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/invalid-placard.js b/Source/WebCore/Modules/modern-media-controls/controls/invalid-placard.js
new file mode 100644
index 000000000..18d3af29b
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/invalid-placard.js
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+class InvalidPlacard extends Placard
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ iconName: Icons.InvalidPlacard,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css
new file mode 100644
index 000000000..ba683a9d3
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.css
@@ -0,0 +1,132 @@
+/*
+ * 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.
+ */
+
+/* Controls bar */
+
+.media-controls.ios.inline > .controls-bar {
+ left: 0;
+ right: 0;
+ bottom: 0;
+ height: 50px;
+}
+
+.media-controls.ios.inline > .controls-bar:before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+ -webkit-appearance: media-controls-light-bar-background;
+ will-change: transform;
+}
+
+:host(audio) .media-controls.ios.inline > .controls-bar:before {
+ -webkit-appearance: none;
+ background-color: rgb(212, 212, 212);
+}
+
+.media-controls.ios.inline .time-control {
+ position: absolute;
+}
+
+/* Buttons */
+
+.media-controls.ios.inline button {
+ background-color: black;
+}
+
+.media-controls.ios.inline button:active {
+ background-color: white;
+}
+
+.media-controls.ios.inline > .controls-bar button {
+ height: 100% !important;
+}
+
+/* Make right container flush to the right */
+
+.media-controls.ios.inline .buttons-container.right {
+ right: 0;
+}
+
+/* Buttons placement */
+
+.media-controls.ios.inline button.play-pause {
+ -webkit-mask-position-y: 12px;
+}
+
+.media-controls.ios.inline button.skip-back {
+ -webkit-mask-position-y: 10px;
+}
+
+.media-controls.ios.inline button.airplay {
+ -webkit-mask-position-y: 13px;
+}
+
+.media-controls.ios.inline button.pip {
+ -webkit-mask-position-y: 13px;
+}
+
+.media-controls.ios.inline button.fullscreen {
+ -webkit-mask-position-y: 13px;
+}
+
+/* Time labels */
+
+.media-controls.ios.inline .time-label {
+ top: 14.5px;
+ color: black;
+}
+
+/* Scrubber */
+
+.media-controls.ios.inline .scrubber.slider {
+ top: 13px;
+}
+
+.media-controls.ios.inline .scrubber.slider > div {
+ position: absolute;
+ top: 10px;
+ left: 2px;
+ right: 2px;
+ height: 3px;
+ border-radius: 1.5px;
+ background-color: rgba(0, 0, 0, 0.55);
+ mix-blend-mode: plus-darker;
+}
+
+.media-controls.ios.inline .scrubber.slider > input::-webkit-slider-thumb {
+ width: 15px;
+ height: 50px;
+ background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAiCAYAAABIiGl0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAxNpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iUGl4ZWxtYXRvciAyLjIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NTkwQ0UwODdBQTcxMTFFNEE5QTZGQTVGMjFBNkUxN0UiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NTkwQ0UwODhBQTcxMTFFNEE5QTZGQTVGMjFBNkUxN0UiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo1OTBDRTA4NUFBNzExMUU0QTlBNkZBNUYyMUE2RTE3RSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo1OTBDRTA4NkFBNzExMUU0QTlBNkZBNUYyMUE2RTE3RSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pofoz4wAAAJGSURBVHjaxJfNTsJAEMfbLmoNaKIhIE18A+LReOXmi/gQnnwSLz6Fnjh4Id4kHElI5EDwpIkgImWdf/Nfs5ISCrR1kkmg7c5vZz/mw3WSy66oL7ojqqiQkPotOhGdaq1XGnMTvC+KlprN5kW9Xr8sFotnhUKhCsUHs9lsCB2NRu1Op3PfaDRa8vhDdCSqnQ0E3lX7/f6NGH7RCQXfYgzG0sZacthut6/G4/Gj3lAwFjZgKyn0qNfrXYdh+Ka3FNiALdhc6Sk+1CkL4Us997E0aXga5zmX3Y87vdVt9jTJnvPA/blJJZxEnbHwtJds8Mk6V2ZTAQMsAD1EJAQHpdSpk7GAARaYAPuISE5OQpYfeYwwmBeYrMhjZeJuHkKWAtj7B7DnJchQaQsylgvwHGktL6qwXsH0TE7NETw091gjiecFFtYzmNFSo3LICyysBzBxsI5xoWUJWllHL8lSfTnViFyTyGO4PhgMbrP2lgxNpnPAdBXkkBYDsg48lqbRDLrd7t18Pn9P21PYhG3zl8yoXsY+1zCjDEufgIxjMqPCHMm5wpdBBsVeQK2QpUzZs8dKsGY+SrG8DSxvj8j6DdOKHUPZhkO3KOiDBWiZDGW3MC4f7FPVYvKQyuE8YQvzFJMUcJg+qfit3YVKc4clqB8H3zAThWzmJmzstGN1fI511LVJXYzl7hZQ00F+2dA4sH3P7Am4a0zAeDklEODZYueoVgz+DS4rWk5tTdj2cmqt4tr9sccJFqyG3N4CGxrSu3AZ0MiPAAMAZrLkuVVmRJsAAAAASUVORK5CYII=");
+ background-repeat: no-repeat;
+ background-size: 15px 17px;
+ background-position: 0px 18px;
+ background-color: transparent;
+ box-shadow: none;
+ border: none;
+ -webkit-appearance: none !important;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.js b/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.js
new file mode 100644
index 000000000..963e22b01
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/ios-inline-media-controls.js
@@ -0,0 +1,109 @@
+/*
+ * 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.
+ */
+
+class IOSInlineMediaControls extends MediaControls
+{
+
+ constructor(options = {})
+ {
+ options.layoutTraits = LayoutTraits.iOS;
+
+ super(options);
+
+ this.element.classList.add("ios");
+ this.element.classList.add("inline");
+
+ this._leftContainer = new ButtonsContainer({
+ buttons: [this.playPauseButton, this.skipBackButton],
+ cssClassName: "left"
+ });
+
+ this._rightContainer = new ButtonsContainer({
+ buttons: [this.airplayButton, this.pipButton, this.fullscreenButton],
+ cssClassName: "right"
+ });
+
+ this.controlsBar.children = [this._leftContainer, this._rightContainer];
+
+ this._pinchGestureRecognizer = new PinchGestureRecognizer(this.element, this);
+ }
+
+ // Protected
+
+ gestureRecognizerStateDidChange(recognizer)
+ {
+ if (this._pinchGestureRecognizer !== recognizer)
+ return;
+
+ if (recognizer.state !== GestureRecognizer.States.Ended && recognizer.state !== GestureRecognizer.States.Changed)
+ return;
+
+ if (recognizer.scale > IOSInlineMediaControls.MinimumScaleToEnterFullscreen && this.delegate && typeof this.delegate.iOSInlineMediaControlsRecognizedPinchInGesture === "function")
+ this.delegate.iOSInlineMediaControlsRecognizedPinchInGesture();
+ }
+
+ // Public
+
+ layout()
+ {
+ super.layout();
+
+ // Reset dropped buttons.
+ for (let button of this._rightContainer.buttons)
+ delete button.dropped;
+
+ this._leftContainer.layout();
+ this._rightContainer.layout();
+
+ this.timeControl.width = this.width - this._leftContainer.width - this._rightContainer.width;
+
+ if (this.timeControl.isSufficientlyWide) {
+ this.controlsBar.insertBefore(this.timeControl, this._rightContainer);
+ this.timeControl.x = this._leftContainer.width;
+ } else {
+ this.timeControl.remove();
+ // Since we don't have enough space to display the scrubber, we may also not have
+ // enough space to display all buttons in the left and right containers, so gradually drop them.
+ for (let control of [this.airplayButton, this.pipButton, this.skipBackButton, this.fullscreenButton]) {
+ // Nothing left to do if the combined container widths is shorter than the available width.
+ if (this._leftContainer.width + this._rightContainer.width < this.width)
+ break;
+
+ // If the control was already not participating in layout, we can skip it.
+ if (!control.visible)
+ continue;
+
+ // This control must now be dropped.
+ control.dropped = true;
+
+ this._leftContainer.layout();
+ this._rightContainer.layout();
+ }
+ }
+ }
+
+}
+
+IOSInlineMediaControls.MinimumScaleToEnterFullscreen = 1.5;
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/layout-item.js b/Source/WebCore/Modules/modern-media-controls/controls/layout-item.js
new file mode 100644
index 000000000..a8d188a32
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/layout-item.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+const LayoutTraits = {
+ Unknown : 0,
+ macOS : 1 << 0,
+ iOS : 1 << 1,
+ Fullscreen : 1 << 2,
+ Compact : 1 << 3,
+ ReducedPadding : 1 << 4,
+ TightPadding : 1 << 5
+};
+
+class LayoutItem extends LayoutNode
+{
+
+ constructor({ element = null, layoutDelegate = null } = {})
+ {
+ super(element);
+
+ this.layoutDelegate = layoutDelegate;
+ }
+
+ // Public
+
+ get layoutTraits()
+ {
+ return (this.layoutDelegate && this.layoutDelegate.layoutTraits) || LayoutTraits.Unknown;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js b/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js
new file mode 100644
index 000000000..2a87f27d6
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/layout-node.js
@@ -0,0 +1,307 @@
+
+const dirtyNodes = new Set;
+const nodesRequiringChildrenUpdate = new Set;
+
+class LayoutNode
+{
+
+ constructor(stringOrElement)
+ {
+
+ if (!stringOrElement)
+ this.element = document.createElement("div");
+ else if (stringOrElement instanceof Element)
+ this.element = stringOrElement;
+ else if (typeof stringOrElement === "string" || stringOrElement instanceof String)
+ this.element = elementFromString(stringOrElement);
+
+ this._parent = null;
+ this._children = [];
+
+ this._x = 0;
+ this._y = 0;
+ this._width = 0;
+ this._height = 0;
+ this._visible = true;
+
+ this._needsLayout = false;
+ this._dirtyProperties = new Set;
+
+ this._pendingDOMManipulation = LayoutNode.DOMManipulation.None;
+ }
+
+ get x()
+ {
+ return this._x;
+ }
+
+ set x(x)
+ {
+ if (x === this._x)
+ return;
+
+ this._x = x;
+ this.markDirtyProperty("x");
+ }
+
+ get y()
+ {
+ return this._y;
+ }
+
+ set y(y)
+ {
+ if (y === this._y)
+ return;
+
+ this._y = y;
+ this.markDirtyProperty("y");
+ }
+
+ get width()
+ {
+ return this._width;
+ }
+
+ set width(width)
+ {
+ if (width === this._width)
+ return;
+
+ this._width = width;
+ this.markDirtyProperty("width");
+ }
+
+ get height()
+ {
+ return this._height;
+ }
+
+ set height(height)
+ {
+ if (height === this._height)
+ return;
+
+ this._height = height;
+ this.markDirtyProperty("height");
+ }
+
+ get visible()
+ {
+ return this._visible;
+ }
+
+ set visible(flag)
+ {
+ if (flag === this._visible)
+ return;
+
+ this._visible = flag;
+ this.markDirtyProperty("visible");
+ }
+
+ get needsLayout()
+ {
+ return this._needsLayout || this._pendingDOMManipulation !== LayoutNode.DOMManipulation.None || this._dirtyProperties.size > 0;
+ }
+
+ set needsLayout(flag)
+ {
+ if (this.needsLayout === flag)
+ return;
+
+ this._needsLayout = flag;
+ this._updateDirtyState();
+ }
+
+ get parent()
+ {
+ return this._parent;
+ }
+
+ get children()
+ {
+ return this._children;
+ }
+
+ set children(children)
+ {
+ while (this._children.length)
+ this.removeChild(this._children[0]);
+
+ for (let child of children)
+ this.addChild(child);
+ }
+
+ parentOfType(type)
+ {
+ let node = this;
+ while (node = node._parent) {
+ if (node instanceof type)
+ return node;
+ }
+ return null;
+ }
+
+ addChild(child, index)
+ {
+ child.remove();
+
+ if (index === undefined || index < 0 || index > this._children.length)
+ index = this._children.length;
+
+ this._children.splice(index, 0, child);
+ child._parent = this;
+
+ child._markNodeManipulation(LayoutNode.DOMManipulation.Addition);
+
+ return child;
+ }
+
+ insertBefore(newSibling, referenceSibling)
+ {
+ return this.addChild(newSibling, this._children.indexOf(referenceSibling));
+ }
+
+ insertAfter(newSibling, referenceSibling)
+ {
+ const index = this._children.indexOf(referenceSibling);
+ return this.addChild(newSibling, index + 1);
+ }
+
+ removeChild(child)
+ {
+ if (child._parent !== this)
+ return;
+
+ const index = this._children.indexOf(child);
+ if (index === -1)
+ return;
+
+ this._children.splice(index, 1);
+ child._parent = null;
+
+ child._markNodeManipulation(LayoutNode.DOMManipulation.Removal);
+
+ return child;
+ }
+
+ remove()
+ {
+ if (this._parent instanceof LayoutNode)
+ return this._parent.removeChild(this);
+ }
+
+ markDirtyProperty(propertyName)
+ {
+ const hadProperty = this._dirtyProperties.has(propertyName);
+ this._dirtyProperties.add(propertyName);
+
+ if (!hadProperty)
+ this._updateDirtyState();
+ }
+
+ commitProperty(propertyName)
+ {
+ const style = this.element.style;
+
+ switch (propertyName) {
+ case "x":
+ style.left = `${this._x}px`;
+ break;
+ case "y":
+ style.top = `${this._y}px`;
+ break;
+ case "width":
+ style.width = `${this._width}px`;
+ break;
+ case "height":
+ style.height = `${this._height}px`;
+ break;
+ case "visible":
+ style.display = this._visible ? "inherit" : "none";
+ break;
+ }
+ }
+
+ layout()
+ {
+ if (this._pendingDOMManipulation === LayoutNode.DOMManipulation.Removal) {
+ const parent = this.element.parentNode;
+ if (parent)
+ parent.removeChild(this.element);
+ }
+
+ for (let propertyName of this._dirtyProperties)
+ this.commitProperty(propertyName);
+
+ this._dirtyProperties.clear();
+
+ if (this._pendingDOMManipulation === LayoutNode.DOMManipulation.Addition)
+ nodesRequiringChildrenUpdate.add(this.parent);
+ }
+
+ // Private
+
+ _markNodeManipulation(manipulation)
+ {
+ this._pendingDOMManipulation = manipulation;
+ this._updateDirtyState();
+ }
+
+ _updateDirtyState()
+ {
+ if (this.needsLayout) {
+ dirtyNodes.add(this);
+ scheduler.scheduleLayout(performScheduledLayout);
+ } else {
+ dirtyNodes.delete(this);
+ if (dirtyNodes.size === 0)
+ scheduler.unscheduleLayout(performScheduledLayout);
+ }
+ }
+
+ _updateChildren()
+ {
+ let nextChildElement = null;
+ const element = this.element;
+ for (let i = this.children.length - 1; i >= 0; --i) {
+ let child = this.children[i];
+ let childElement = child.element;
+
+ if (child._pendingDOMManipulation === LayoutNode.DOMManipulation.Addition) {
+ element.insertBefore(childElement, nextChildElement);
+ child._pendingDOMManipulation = LayoutNode.DOMManipulation.None;
+ }
+
+ nextChildElement = childElement;
+ }
+ }
+
+}
+
+LayoutNode.DOMManipulation = {
+ None: 0,
+ Removal: 1,
+ Addition: 2
+};
+
+function performScheduledLayout()
+{
+ const previousDirtyNodes = Array.from(dirtyNodes);
+ dirtyNodes.clear();
+ previousDirtyNodes.forEach(node => {
+ node._needsLayout = false;
+ node.layout();
+ });
+
+ nodesRequiringChildrenUpdate.forEach(node => node._updateChildren());
+ nodesRequiringChildrenUpdate.clear();
+}
+
+function elementFromString(elementString)
+{
+ const element = document.createElement("div");
+ element.innerHTML = elementString;
+ return element.firstElementChild;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-compact-inline-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/macos-compact-inline-media-controls.css
new file mode 100644
index 000000000..456d78957
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-compact-inline-media-controls.css
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+
+/* Controls bar */
+
+.media-controls.mac.inline.compact > .controls-bar {
+ height: 25px;
+}
+
+/* Controls placement */
+
+.media-controls.mac.inline.compact button.play-pause {
+ -webkit-mask-position-y: 6px;
+}
+
+.media-controls.mac.inline.compact button.skip-back {
+ -webkit-mask-position-y: 6px;
+}
+
+.media-controls.mac.inline.compact .scrubber.slider {
+ top: 12px;
+}
+
+.media-controls.mac.inline.compact button.mute {
+ -webkit-mask-position-y: 6px;
+}
+
+.media-controls.mac.inline.compact button.fullscreen {
+ -webkit-mask-position-y: 6.5px;
+}
+
+/* Labels */
+
+.media-controls.mac.inline.compact .time-label,
+.media-controls.mac.inline.compact .status-label {
+ top: 5px;
+ font-size: 12px;
+}
+
+/* Volume slider */
+
+.media-controls.mac.inline.compact .volume-slider-container {
+ height: 21px;
+ transform: rotate(-90deg) translate(5px, -33px);
+}
+
+.media-controls.mac.inline.compact .volume.slider {
+ top: 5px;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css
new file mode 100644
index 000000000..2d7c9766b
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.css
@@ -0,0 +1,119 @@
+/*
+ * 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.
+ */
+
+/* Controls bar */
+
+.media-controls.mac.fullscreen {
+ --controls-bar-width: 468px;
+ --tracks-panel-right-margin: 40px;
+
+ width: 100% !important;
+ height: 100% !important;
+}
+
+.media-controls.mac.fullscreen > .controls-bar {
+ left: calc((100% - var(--controls-bar-width)) / 2);
+ bottom: 25px;
+ width: var(--controls-bar-width);
+ height: 75px;
+ overflow: hidden;
+}
+
+.media-controls.mac.fullscreen > .controls-bar > .background-tint > div {
+ border-radius: 8px;
+}
+
+/* Volume slider */
+
+.media-controls.mac.fullscreen .volume.slider {
+ left: 31px;
+ top: 19px;
+}
+
+.media-controls.mac.fullscreen:not(.uses-ltr-user-interface-layout-direction) .volume.slider {
+ transform: scaleX(-1);
+}
+
+.media-controls.mac.fullscreen button.volume-down {
+ -webkit-mask-position-y: 18px;
+}
+
+.media-controls.mac.fullscreen button.volume-up {
+ -webkit-mask-position-y: 17px;
+}
+
+/* Button containers */
+
+.media-controls.mac.fullscreen .buttons-container {
+ height: 44px;
+}
+
+.media-controls.mac.fullscreen .buttons-container.center {
+ left: 50%;
+ top: 0;
+ transform: translateX(-50%);
+}
+
+/* Buttons placement for center container */
+
+.media-controls.mac.fullscreen button.rewind {
+ -webkit-mask-position-y: 17px;
+}
+
+.media-controls.mac.fullscreen button.play-pause {
+ -webkit-mask-position-y: 12px;
+}
+
+.media-controls.mac.fullscreen button.forward {
+ -webkit-mask-position-y: 17px;
+}
+
+/* Make right container flush to the right */
+
+.media-controls.mac.fullscreen .buttons-container.right {
+ right: 0;
+}
+
+/* Buttons placement for right container */
+
+.media-controls.mac.fullscreen .buttons-container.right button {
+ -webkit-mask-position-y: 18px;
+}
+
+/* Scrubber */
+
+.media-controls.mac.fullscreen .time-control {
+ position: absolute;
+ left: 10px;
+ top: 48px;
+}
+
+.media-controls.mac.fullscreen .time-label {
+ font-size: 12px;
+}
+
+.media-controls.mac.fullscreen .scrubber {
+ top: -3px;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.js b/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.js
new file mode 100644
index 000000000..2bebd171c
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-fullscreen-media-controls.js
@@ -0,0 +1,173 @@
+/*
+ * 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.
+ */
+
+const ButtonMarginForThreeButtonsOrLess = 24;
+const ButtonMarginForFourButtons = 16;
+const ButtonMarginForFiveButtons = 12;
+const FullscreenTimeControlWidth = 457;
+
+class MacOSFullscreenMediaControls extends MacOSMediaControls
+{
+
+ constructor(options = {})
+ {
+ options.layoutTraits = LayoutTraits.macOS | LayoutTraits.Fullscreen;
+
+ super(options);
+
+ this.element.classList.add("fullscreen");
+
+ // Set up fullscreen-specific buttons.
+ this.volumeDownButton = new VolumeDownButton(this);
+ this.volumeUpButton = new VolumeUpButton(this);
+ this.rewindButton = new RewindButton(this);
+ this.forwardButton = new ForwardButton(this);
+ this.fullscreenButton.isFullscreen = true;
+
+ this.volumeSlider.width = 60;
+
+ this._leftContainer = new ButtonsContainer({
+ buttons: [this.volumeDownButton, this.volumeSlider, this.volumeUpButton],
+ cssClassName: "left",
+ leftMargin: 12,
+ rightMargin: 0,
+ buttonMargin: 6
+ });
+
+ this._centerContainer = new ButtonsContainer({
+ buttons: [this.rewindButton, this.playPauseButton, this.forwardButton],
+ cssClassName: "center",
+ leftMargin: 27,
+ rightMargin: 27,
+ buttonMargin: 27
+ });
+
+ this._rightContainer = new ButtonsContainer({
+ buttons: [this.airplayButton, this.pipButton, this.tracksButton, this.fullscreenButton],
+ cssClassName: "right",
+ leftMargin: 12,
+ rightMargin: 12
+ });
+
+ this.controlsBar.children = [new BackgroundTint, this._leftContainer, this._centerContainer, this._rightContainer, this.timeControl];
+
+ this.element.addEventListener("mousedown", this);
+ }
+
+ // Public
+
+ showTracksPanel()
+ {
+ super.showTracksPanel();
+
+ const tracksButtonBounds = this.tracksButton.element.getBoundingClientRect();
+ this.tracksPanel.rightX = window.innerWidth - tracksButtonBounds.right;
+ this.tracksPanel.bottomY = window.innerHeight - tracksButtonBounds.top + 1;
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "mousedown":
+ this._handleMousedown(event);
+ break;
+ case "mousemove":
+ this._handleMousemove(event);
+ break;
+ case "mouseup":
+ this._handleMouseup(event);
+ break;
+ }
+ }
+
+ layout()
+ {
+ super.layout();
+
+ const numberOfEnabledButtons = this._rightContainer.buttons.filter(button => button.enabled).length;
+
+ let buttonMargin = ButtonMarginForFiveButtons;
+ if (numberOfEnabledButtons === 4)
+ buttonMargin = ButtonMarginForFourButtons;
+ else if (numberOfEnabledButtons <= 3)
+ buttonMargin = ButtonMarginForThreeButtonsOrLess;
+
+ this._rightContainer.buttonMargin = buttonMargin;
+
+ this._centerContainer.layout();
+ this._rightContainer.layout();
+
+ this.timeControl.width = FullscreenTimeControlWidth;
+ }
+
+ // Private
+
+ _handleMousedown(event)
+ {
+ super.handleEvent(event);
+
+ if (event.target !== this.controlsBar.element)
+ return;
+
+ event.preventDefault();
+
+ this._lastDragPoint = this._pointForEvent(event);
+
+ this.element.addEventListener("mousemove", this, true);
+ this.element.addEventListener("mouseup", this, true);
+ }
+
+ _handleMousemove(event)
+ {
+ event.preventDefault();
+
+ const currentDragPoint = this._pointForEvent(event);
+
+ this.controlsBar.translation = new DOMPoint(
+ this.controlsBar.translation.x + currentDragPoint.x - this._lastDragPoint.x,
+ this.controlsBar.translation.y + currentDragPoint.y - this._lastDragPoint.y
+ );
+
+ this._lastDragPoint = currentDragPoint;
+ }
+
+ _handleMouseup(event)
+ {
+ event.preventDefault();
+
+ delete this._lastDragPoint;
+
+ this.element.removeEventListener("mousemove", this, true);
+ this.element.removeEventListener("mouseup", this, true);
+ }
+
+ _pointForEvent(event)
+ {
+ return new DOMPoint(event.clientX, event.clientY);
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css
new file mode 100644
index 000000000..1c5892dc9
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.css
@@ -0,0 +1,118 @@
+/*
+ * 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.
+ */
+
+/* Controls bar */
+
+.media-controls.mac.inline > .controls-bar {
+ left: 0;
+ bottom: 0;
+ width: 100%;
+ height: 50px;
+}
+
+.media-controls.mac.inline > .controls-bar > * {
+ position: absolute;
+}
+
+/* Start button blur */
+
+.media-controls.mac.inline > button.start > div {
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+}
+
+/* Controls placement */
+
+.media-controls.mac.inline button.play-pause {
+ -webkit-mask-position-y: 12px;
+}
+
+.media-controls.mac.inline button.skip-back {
+ -webkit-mask-position-y: 10px;
+}
+
+.media-controls.mac.inline .scrubber.slider {
+ top: 13px;
+}
+
+.media-controls.mac.inline button.mute {
+ -webkit-mask-position-y: 10px;
+}
+
+.media-controls.mac.inline button.airplay {
+ -webkit-mask-position-y: 13px;
+}
+
+.media-controls.mac.inline button.pip {
+ -webkit-mask-position-y: 13px;
+}
+
+.media-controls.mac.inline button.tracks {
+ -webkit-mask-position-y: 15px;
+}
+
+.media-controls.mac.inline button.fullscreen {
+ -webkit-mask-position-y: 13px;
+}
+
+/* Labels */
+
+.media-controls.mac.inline .time-label,
+.media-controls.mac.inline .status-label {
+ top: 14.5px;
+}
+
+/* Volume slider */
+
+.media-controls.mac.inline .volume-slider-container {
+ position: absolute;
+
+ bottom: 50px;
+ width: 81px;
+ height: 31px;
+ transform: rotate(-90deg) translate(25px, -25px);
+}
+
+.media-controls.mac.inline .volume-slider-container > .background-tint {
+ top: 0;
+ left: 1px;
+ right: 0;
+ bottom: 0px;
+ width: auto;
+}
+
+.media-controls.mac.inline .volume-slider-container > .background-tint > div {
+ border-radius: 0 4px 4px 0;
+}
+
+.media-controls.mac.inline .volume.slider {
+ left: 11px;
+ top: 10px;
+}
+
+/* Tracks Panel */
+
+.media-controls.mac.inline .tracks-panel {
+ bottom: 51px;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.js b/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.js
new file mode 100644
index 000000000..29e69705a
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-inline-media-controls.js
@@ -0,0 +1,202 @@
+/*
+ * 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.
+ */
+
+class MacOSInlineMediaControls extends MacOSMediaControls
+{
+
+ constructor(options)
+ {
+ super(options);
+
+ this.element.classList.add("inline");
+
+ this.leftContainer = new ButtonsContainer({
+ buttons: [this.playPauseButton, this.skipBackButton],
+ cssClassName: "left"
+ });
+
+ this.rightContainer = new ButtonsContainer({
+ cssClassName: "right"
+ });
+
+ this._matchLayoutTraits();
+
+ this._backgroundTint = new BackgroundTint;
+
+ this._volumeSliderContainer = new LayoutNode(`<div class="volume-slider-container"></div>`);
+ this._volumeSliderContainer.children = [new BackgroundTint, this.volumeSlider];
+ this._volumeSliderContainer.visible = false;
+ this.volumeSlider.width = 60;
+
+ // Wire up events to display the volume slider.
+ this.muteButton.element.addEventListener("mouseenter", this);
+ this.muteButton.element.addEventListener("mouseleave", this);
+ this._volumeSliderContainer.element.addEventListener("mouseleave", this);
+
+ this.controlsBar.children = [this._backgroundTint, this.leftContainer, this.rightContainer, this._volumeSliderContainer];
+ }
+
+ // Public
+
+ get layoutTraits()
+ {
+ return this._layoutTraits;
+ }
+
+ set layoutTraits(layoutTraits)
+ {
+ if (this._layoutTraits === layoutTraits)
+ return;
+
+ this._layoutTraits = layoutTraits;
+ this._matchLayoutTraits();
+ }
+
+ layout()
+ {
+ super.layout();
+
+ if (!this.controlsBar.visible)
+ return;
+
+ // Reset dropped buttons.
+ this.rightContainer.buttons.concat(this.leftContainer.buttons).forEach(button => delete button.dropped);
+
+ this.leftContainer.layout();
+ this.rightContainer.layout();
+
+ const middleContainer = this.statusLabel.enabled ? this.statusLabel : this.timeControl;
+ this.controlsBar.children = [this._backgroundTint, this.leftContainer, middleContainer, this.rightContainer, this._volumeSliderContainer];
+
+ if (middleContainer === this.timeControl)
+ this.timeControl.width = this.width - this.leftContainer.width - this.rightContainer.width;
+
+ if (middleContainer === this.timeControl && this.timeControl.isSufficientlyWide)
+ this.timeControl.x = this.leftContainer.width;
+ else {
+ this.timeControl.remove();
+
+ let droppedControls = false;
+
+ // Since we don't have enough space to display the scrubber, we may also not have
+ // enough space to display all buttons in the left and right containers, so gradually drop them.
+ for (let button of [this.airplayButton, this.pipButton, this.tracksButton, this.muteButton, this.skipBackButton, this.fullscreenButton]) {
+ // Nothing left to do if the combined container widths is shorter than the available width.
+ if (this.leftContainer.width + this.rightContainer.width < this.width)
+ break;
+
+ droppedControls = true;
+
+ // If the button was already not participating in layout, we can skip it.
+ if (!button.visible)
+ continue;
+
+ // This button must now be dropped.
+ button.dropped = true;
+
+ this.leftContainer.layout();
+ this.rightContainer.layout();
+ }
+
+ // We didn't need to drop controls and we have status text to show.
+ if (!droppedControls && middleContainer === this.statusLabel) {
+ this.statusLabel.x = this.leftContainer.width;
+ this.statusLabel.width = this.width - this.leftContainer.width - this.rightContainer.width;
+ }
+ }
+
+ this.rightContainer.x = this.width - this.rightContainer.width;
+ 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)
+ {
+ super.handleEvent(event);
+ this._volumeSliderContainer.visible = event.type === "mouseenter" || event.relatedTarget === this._volumeSliderContainer.element;
+ }
+
+ controlsBarVisibilityDidChange(controlsBar)
+ {
+ if (controlsBar.visible)
+ this.layout();
+ }
+
+ // Private
+
+ _matchLayoutTraits()
+ {
+ if (!this.leftContainer || !this.rightContainer)
+ return;
+
+ const layoutTraits = this.layoutTraits;
+ if (layoutTraits & LayoutTraits.Compact) {
+ this.leftContainer.leftMargin = 8;
+ this.leftContainer.rightMargin = 12;
+ this.leftContainer.buttonMargin = 12;
+ this.rightContainer.leftMargin = 12;
+ this.rightContainer.rightMargin = 8;
+ this.rightContainer.buttonMargin = 12;
+ } else if (layoutTraits & LayoutTraits.TightPadding) {
+ this.leftContainer.leftMargin = 12;
+ this.leftContainer.rightMargin = 12;
+ this.leftContainer.buttonMargin = 12;
+ this.rightContainer.leftMargin = 12;
+ this.rightContainer.rightMargin = 12;
+ this.rightContainer.buttonMargin = 12;
+ } else if (layoutTraits & LayoutTraits.ReducedPadding) {
+ this.leftContainer.leftMargin = 12;
+ this.leftContainer.rightMargin = 16;
+ this.leftContainer.buttonMargin = 16;
+ this.rightContainer.leftMargin = 0;
+ this.rightContainer.rightMargin = 12;
+ this.rightContainer.buttonMargin = 16;
+ } else {
+ this.leftContainer.leftMargin = 24;
+ this.leftContainer.rightMargin = 24;
+ this.leftContainer.buttonMargin = 24;
+ this.rightContainer.leftMargin = 24;
+ this.rightContainer.rightMargin = 24;
+ this.rightContainer.buttonMargin = 24;
+ }
+
+ if (layoutTraits & LayoutTraits.Compact)
+ this.rightContainer.buttons = [this.muteButton, this.fullscreenButton];
+ else
+ this.rightContainer.buttons = [this.muteButton, this.airplayButton, this.pipButton, this.tracksButton, this.fullscreenButton];
+
+ this.leftContainer.buttons.forEach(button => button.layoutTraitsDidChange());
+ this.rightContainer.buttons.forEach(button => button.layoutTraitsDidChange());
+
+ this.element.classList.toggle("compact", layoutTraits & LayoutTraits.Compact);
+ }
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css
new file mode 100644
index 000000000..bb16d9f9d
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.css
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/* Buttons in controls bar */
+
+.media-controls.mac button:active {
+ background-color: white;
+}
+
+.media-controls.mac > .controls-bar button {
+ height: 100% !important;
+ background-color: rgba(255, 255, 255, 0.45);
+ mix-blend-mode: plus-lighter;
+}
+
+.media-controls.mac > .controls-bar .time-label {
+ color: rgba(255, 255, 255, 0.45);
+ mix-blend-mode: plus-lighter;
+}
+
+.media-controls.mac > .controls-bar .slider > canvas {
+ mix-blend-mode: plus-lighter;
+}
+
+.media-controls.mac > .controls-bar .slider > input::-webkit-slider-thumb {
+ width: 3px !important;
+ height: 100% !important;
+ -webkit-appearance: none !important;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js b/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js
new file mode 100644
index 000000000..85cb875a6
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/macos-media-controls.js
@@ -0,0 +1,81 @@
+/*
+ * 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.
+ */
+
+class MacOSMediaControls extends MediaControls
+{
+
+ constructor({ width, height, layoutTraits = LayoutTraits.macOS } = {})
+ {
+ super({ width, height, layoutTraits });
+
+ this.element.classList.add("mac");
+
+ this.muteButton = new MuteButton(this);
+ this.tracksButton = new TracksButton(this);
+ this.tracksPanel = new TracksPanel;
+ this.volumeSlider = new VolumeSlider;
+
+ this.element.addEventListener("mousedown", this);
+ this.element.addEventListener("click", this);
+ }
+
+ // Public
+
+ showTracksPanel()
+ {
+ this.tracksButton.on = true;
+ this.tracksButton.element.blur();
+ this.controlsBar.userInteractionEnabled = false;
+ this.tracksPanel.presentInParent(this);
+ }
+
+ hideTracksPanel()
+ {
+ this.tracksButton.on = false;
+ this.tracksButton.element.focus();
+ this.controlsBar.userInteractionEnabled = true;
+ this.tracksPanel.hide();
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ if (event.currentTarget !== this.element)
+ return;
+
+ // Only notify that the background was clicked when the "mousedown" event
+ // was also received, which wouldn't happen if the "mousedown" event caused
+ // the tracks panel to be hidden.
+ if (event.type === "mousedown")
+ this._receivedMousedown = true;
+ else if (event.type === "click") {
+ if (this._receivedMousedown && event.target === this.element && this.delegate && typeof this.delegate.macOSControlsBackgroundWasClicked === "function")
+ this.delegate.macOSControlsBackgroundWasClicked();
+ delete this._receivedMousedown
+ }
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css b/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css
new file mode 100644
index 000000000..d5d02595c
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/media-controls.css
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+:host(audio) {
+ width: 200px;
+ height: 50px;
+}
+
+/* We need to use relative positioning due to webkit.org/b/163603 */
+.media-controls-container {
+ position: relative;
+}
+
+.media-controls-container,
+.media-controls-container > * {
+ left: 0;
+ top: 0;
+ width: 100%;
+}
+
+.media-controls-container,
+.media-controls-container * {
+ -webkit-text-zoom: reset;
+ -webkit-text-size-adjust: auto;
+}
+
+.media-controls-container > * {
+ position: absolute;
+}
+
+.media-controls {
+ height: 100%;
+ font-family: -apple-system;
+ -webkit-user-select: none;
+ white-space: nowrap;
+ cursor: default;
+}
+
+:host(:-webkit-animating-full-screen-transition) .media-controls {
+ display: none;
+}
+
+.media-controls > .controls-bar {
+ position: absolute;
+}
+
+.media-controls.fade-in {
+ animation-name: fade-in;
+ animation-duration: 350ms;
+}
+
+@keyframes fade-in {
+ from { opacity: 0 }
+ to { opacity: 1 }
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/media-controls.js b/Source/WebCore/Modules/modern-media-controls/controls/media-controls.js
new file mode 100644
index 000000000..30687c5ea
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/media-controls.js
@@ -0,0 +1,148 @@
+/*
+ * 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.
+ */
+
+class MediaControls extends LayoutNode
+{
+
+ constructor({ width = 300, height = 150, layoutTraits = LayoutTraits.Unknown } = {})
+ {
+ super(`<div class="media-controls"></div>`);
+
+ this._scaleFactor = 1;
+
+ this.width = width;
+ this.height = height;
+ this.layoutTraits = layoutTraits;
+
+ this.startButton = new StartButton(this);
+
+ this.playPauseButton = new PlayPauseButton(this);
+ this.skipBackButton = new SkipBackButton(this);
+ this.airplayButton = new AirplayButton(this);
+ this.pipButton = new PiPButton(this);
+ this.fullscreenButton = new FullscreenButton(this);
+
+ this.statusLabel = new StatusLabel(this);
+ this.timeControl = new TimeControl(this);
+
+ this.controlsBar = new ControlsBar(this);
+
+ this.airplayPlacard = new AirplayPlacard(this);
+ this.invalidPlacard = new InvalidPlacard(this);
+ this.pipPlacard = new PiPPlacard(this);
+
+ this.showsStartButton = false;
+ }
+
+ // Public
+
+ get showsStartButton()
+ {
+ return !!this._showsStartButton;
+ }
+
+ set showsStartButton(flag)
+ {
+ if (this._showsStartButton === flag)
+ return;
+
+ this._showsStartButton = flag;
+ this._invalidateChildren();
+ }
+
+ get usesLTRUserInterfaceLayoutDirection()
+ {
+ return this.element.classList.contains("uses-ltr-user-interface-layout-direction");
+ }
+
+ set usesLTRUserInterfaceLayoutDirection(flag)
+ {
+ this.element.classList.toggle("uses-ltr-user-interface-layout-direction", flag);
+ }
+
+ get scaleFactor()
+ {
+ return this._scaleFactor;
+ }
+
+ set scaleFactor(scaleFactor)
+ {
+ if (this._scaleFactor === scaleFactor)
+ return;
+
+ this._scaleFactor = scaleFactor;
+ this.markDirtyProperty("scaleFactor");
+ }
+
+ get showsPlacard()
+ {
+ return this.children[0] instanceof Placard;
+ }
+
+ showPlacard(placard)
+ {
+ const children = [placard];
+ if (placard === this.airplayPlacard)
+ children.push(this.controlsBar);
+
+ this.children = children;
+ }
+
+ hidePlacard()
+ {
+ if (this.showsPlacard)
+ this.children[0].remove();
+ this._invalidateChildren();
+ }
+
+ fadeIn()
+ {
+ this.element.classList.add("fade-in");
+ }
+
+ // Protected
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "scaleFactor")
+ this.element.style.zoom = 1 / this._scaleFactor;
+ else
+ super.commitProperty(propertyName);
+ }
+
+ controlsBarVisibilityDidChange(controlsBar)
+ {
+ // Implemented by subclasses as needed.
+ }
+
+ // Private
+
+ _invalidateChildren()
+ {
+ if (!this.showsPlacard)
+ this.children = [this._showsStartButton ? this.startButton : this.controlsBar];
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/mute-button.js b/Source/WebCore/Modules/modern-media-controls/controls/mute-button.js
new file mode 100644
index 000000000..a879a4ff1
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/mute-button.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+class MuteButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "mute",
+ iconName: Icons.Volume,
+ layoutDelegate
+ });
+ }
+
+ // Public
+
+ get muted()
+ {
+ return this.iconName === Icons.VolumeMuted;
+ }
+
+ set muted(flag)
+ {
+ if (this.muted === flag)
+ return;
+
+ this.iconName = flag ? Icons.VolumeMuted : Icons.Volume;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/pip-button.js b/Source/WebCore/Modules/modern-media-controls/controls/pip-button.js
new file mode 100644
index 000000000..fe0780921
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/pip-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class PiPButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "pip",
+ iconName: Icons.EnterPiP,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/pip-placard.js b/Source/WebCore/Modules/modern-media-controls/controls/pip-placard.js
new file mode 100644
index 000000000..1ee8bb82a
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/pip-placard.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class PiPPlacard extends Placard
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ iconName: Icons.PiPPlacard,
+ description: UIString("This video is playing in Picture in Picture"),
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/placard.css b/Source/WebCore/Modules/modern-media-controls/controls/placard.css
new file mode 100644
index 000000000..a8415a69c
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/placard.css
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+.placard {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+
+ background-color: black;
+ color: rgb(164, 164, 164);
+}
+
+.placard .container {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ max-width: 402px;
+
+ transform: translate(-50%, -50%);
+}
+
+.placard .icon {
+ position: relative;
+ left: 50%;
+ -webkit-mask-repeat: no-repeat;
+ background-color: rgb(164, 164, 164) !important;
+
+ margin-bottom: 10px;
+
+ transform: translateX(-50%);
+
+ pointer-events: none;
+}
+
+.placard .title,
+.placard .description {
+ text-align: center;
+}
+
+.placard .title {
+ font-size: 20px;
+}
+
+.placard .description {
+ font-size: 13px;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/placard.js b/Source/WebCore/Modules/modern-media-controls/controls/placard.js
new file mode 100644
index 000000000..73ad5e10f
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/placard.js
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+class Placard extends LayoutItem
+{
+
+ constructor({ iconName = null, title = "", description = "", layoutDelegate = null } = {})
+ {
+ super({
+ element: `<div class="placard"></div>`,
+ layoutDelegate
+ });
+
+ const container = this.addChild(new LayoutNode(`<div class="container"></div>`));
+
+ if (iconName)
+ container.addChild(new IconButton(this)).iconName = iconName;
+
+ if (!!title)
+ container.addChild(new LayoutNode(`<div class="title">${title}</div>`));
+
+ if (!!description)
+ container.addChild(new LayoutNode(`<div class="description">${description}</div>`));
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/play-pause-button.js b/Source/WebCore/Modules/modern-media-controls/controls/play-pause-button.js
new file mode 100644
index 000000000..4b9314939
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/play-pause-button.js
@@ -0,0 +1,53 @@
+/*
+ * 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.
+ */
+
+class PlayPauseButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "play-pause",
+ iconName: Icons.Play,
+ layoutDelegate
+ });
+ }
+
+ // Public
+
+ get playing()
+ {
+ return this.iconName === Icons.Pause;
+ }
+
+ set playing(flag)
+ {
+ if (this.playing === flag)
+ return;
+
+ this.iconName = flag ? Icons.Pause : Icons.Play;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/rewind-button.js b/Source/WebCore/Modules/modern-media-controls/controls/rewind-button.js
new file mode 100644
index 000000000..9f2bab5f3
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/rewind-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class RewindButton extends SeekButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "rewind",
+ iconName: Icons.Rewind,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js b/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js
new file mode 100644
index 000000000..f85beb037
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/scheduler.js
@@ -0,0 +1,66 @@
+
+const scheduler = new class
+{
+
+ constructor()
+ {
+ this._frameID = -1;
+ this._layoutCallbacks = new Set;
+ }
+
+ // Public
+
+ get hasScheduledLayoutCallbacks()
+ {
+ return this._frameID !== -1 || this._layoutCallbacks.size > 0;
+ }
+
+ scheduleLayout(callback)
+ {
+ if (typeof callback !== "function")
+ return;
+
+ this._layoutCallbacks.add(callback);
+ this._requestFrameIfNeeded();
+ }
+
+ unscheduleLayout(callback)
+ {
+ if (typeof callback !== "function")
+ return;
+
+ this._layoutCallbacks.delete(callback);
+ }
+
+ // Private
+
+ _requestFrameIfNeeded()
+ {
+ if (this._frameID === -1 && this._layoutCallbacks.size > 0)
+ this._frameID = window.requestAnimationFrame(this._frameDidFire.bind(this));
+ }
+
+ _frameDidFire()
+ {
+ if (typeof scheduler.frameWillFire === "function")
+ scheduler.frameWillFire();
+
+ this._layout();
+ this._frameID = -1;
+ this._requestFrameIfNeeded();
+
+ if (typeof scheduler.frameDidFire === "function")
+ scheduler.frameDidFire();
+ }
+
+ _layout()
+ {
+ // Layouts are not re-entrant.
+ const layoutCallbacks = this._layoutCallbacks;
+ this._layoutCallbacks = new Set;
+
+ for (let callback of layoutCallbacks)
+ callback();
+ }
+
+};
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/scrubber.js b/Source/WebCore/Modules/modern-media-controls/controls/scrubber.js
new file mode 100644
index 000000000..499399636
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/scrubber.js
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+class Scrubber extends Slider
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "scrubber",
+ layoutDelegate
+ });
+
+ this.height = 23;
+
+ // Add the element used to draw the track on iOS.
+ if (this.layoutTraits & LayoutTraits.iOS)
+ this.addChild(new LayoutNode(`<div></div>`), 0);
+
+ this._buffered = 0;
+ }
+
+ // Public
+
+ get buffered()
+ {
+ return this._buffered;
+ }
+
+ set buffered(buffered)
+ {
+ if (this._buffered === buffered)
+ return;
+
+ this._buffered = buffered;
+ this.needsLayout = true;
+ }
+
+ // Protected
+
+ draw(ctx)
+ {
+ const width = this.width;
+ const height = this.height;
+
+ if (!this.width || !this.height)
+ return;
+
+ const dpr = window.devicePixelRatio;
+
+ ctx.save();
+ ctx.scale(dpr, dpr);
+ ctx.clearRect(0, 0, width, height);
+
+ const layoutTraits = this.layoutTraits;
+ if (layoutTraits & LayoutTraits.macOS)
+ this._drawMacOS(ctx, width, height);
+ else if (layoutTraits & LayoutTraits.iOS)
+ this._drawiOS(ctx, width, height);
+
+ ctx.restore();
+ }
+
+ _drawMacOS(ctx, width, height)
+ {
+ const trackHeight = 3;
+ const trackY = (height - trackHeight) / 2;
+ const scrubberWidth = 4;
+ const scrubberHeight = height;
+ const borderSize = 2;
+ const scrubberPosition = Math.max(0, Math.min(width - scrubberWidth, Math.round(width * this.value)));
+
+ // Draw background.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, 0, trackY, width, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(20, 20, 20)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+
+ // Buffered.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, 0, trackY, width, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(39, 39, 39)";
+ ctx.fillRect(0, 0, width * this._buffered, height);
+ ctx.restore();
+
+ // Draw played section.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, 0, trackY, width, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(84, 84, 84)";
+ ctx.fillRect(0, 0, width * this.value, height);
+ ctx.restore();
+
+ // Draw the scrubber.
+ ctx.save();
+ ctx.clearRect(scrubberPosition - 1, 0, scrubberWidth + borderSize, height, 0);
+ ctx.beginPath();
+ addRoundedRect(ctx, scrubberPosition, 0, scrubberWidth, scrubberHeight, 1);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(138, 138, 138)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+ }
+
+ _drawiOS(ctx, width, height)
+ {
+ const trackHeight = 3;
+ const trackY = (height - trackHeight) / 2;
+ const scrubberWidth = 15;
+ const leftPadding = 2;
+ const rightPadding = 2;
+ const trackWidth = this.width - leftPadding - rightPadding - scrubberWidth;
+
+ // Draw played section.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, leftPadding, trackY, scrubberWidth / 2 + trackWidth * this.value, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.fillStyle = "white";
+ ctx.fill();
+ ctx.restore();
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/seek-button.js b/Source/WebCore/Modules/modern-media-controls/controls/seek-button.js
new file mode 100644
index 000000000..c72c1f165
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/seek-button.js
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+class SeekButton extends IconButton
+{
+
+ constructor(options)
+ {
+ super(options);
+
+ this.element.addEventListener("mousedown", this);
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ if (event.type === "mousedown" && event.currentTarget === this.element)
+ this._didStartPressing();
+ else if (event.type === "mouseup")
+ this._didStopPressing();
+ else
+ super.handleEvent(event);
+ }
+
+ // Private
+
+ _didStartPressing()
+ {
+ const mediaControls = this.parentOfType(MediaControls);
+ if (!mediaControls)
+ return;
+
+ this._mouseupTarget = mediaControls.element;
+ this._mouseupTarget.addEventListener("mouseup", this, true);
+ this._notifyDelegateOfPressingState(true);
+ }
+
+ _didStopPressing()
+ {
+ this._mouseupTarget.removeEventListener("mouseup", this, true);
+ this._notifyDelegateOfPressingState(false);
+ }
+
+ _notifyDelegateOfPressingState(isPressed)
+ {
+ if (this._enabled && this.uiDelegate && typeof this.uiDelegate.buttonPressedStateDidChange === "function")
+ this.uiDelegate.buttonPressedStateDidChange(this, isPressed);
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/skip-back-button.js b/Source/WebCore/Modules/modern-media-controls/controls/skip-back-button.js
new file mode 100644
index 000000000..c5c2d0c2a
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/skip-back-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class SkipBackButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "skip-back",
+ iconName: Icons.SkipBack,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/slider.css b/Source/WebCore/Modules/modern-media-controls/controls/slider.css
new file mode 100644
index 000000000..cb5ab15b7
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/slider.css
@@ -0,0 +1,47 @@
+/*
+ * 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.
+ */
+
+.slider {
+ position: absolute;
+}
+
+.slider > canvas,
+.slider > input {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+}
+
+.slider > canvas {
+ pointer-events: none;
+}
+
+.slider > input {
+ margin: 0;
+ background-color: transparent;
+ -webkit-appearance: none !important;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/slider.js b/Source/WebCore/Modules/modern-media-controls/controls/slider.js
new file mode 100644
index 000000000..c32d662b8
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/slider.js
@@ -0,0 +1,152 @@
+/*
+ * 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.
+ */
+
+class Slider extends LayoutItem
+{
+
+ constructor({ layoutDelegate = null, cssClassName = "" } = {})
+ {
+ super({
+ element: `<div class="slider ${cssClassName}"></div>`,
+ layoutDelegate
+ });
+
+ this._canvas = new LayoutNode(`<canvas></canvas>`);
+
+ this._input = new LayoutNode(`<input type="range" min="0" max="1" step="0.001" />`);
+ this._input.element.addEventListener("change", this);
+ this._input.element.addEventListener("input", this);
+
+ this.value = 0;
+
+ this.children = [this._canvas, this._input];
+ }
+
+ // Public
+
+ get value()
+ {
+ if (this._value !== undefined)
+ return this._value;
+ return parseFloat(this._input.element.value);
+ }
+
+ set value(value)
+ {
+ if (this._valueIsChanging)
+ return;
+
+ this._value = value;
+ this.markDirtyProperty("value");
+ this.needsLayout = true;
+ }
+
+ get width()
+ {
+ return super.width;
+ }
+
+ set width(width)
+ {
+ super.width = width;
+ this.needsLayout = true;
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "input":
+ this._handleInputEvent();
+ break;
+ case "change":
+ this._handleChangeEvent();
+ break;
+ }
+ }
+
+ commitProperty(propertyName)
+ {
+ switch (propertyName) {
+ case "value":
+ this._input.element.value = this._value;
+ delete this._value;
+ break;
+ case "width":
+ this._canvas.element.width = this.width * window.devicePixelRatio;
+ case "height":
+ this._canvas.element.height = this.height * window.devicePixelRatio;
+ default :
+ super.commitProperty(propertyName);
+ break;
+ }
+ }
+
+ layout()
+ {
+ super.layout();
+ this.draw(this._canvas.element.getContext("2d"));
+ }
+
+ draw(ctx)
+ {
+ // Implemented by subclasses.
+ }
+
+ // Private
+
+ _handleInputEvent()
+ {
+ if (!this._valueIsChanging && this.uiDelegate && typeof this.uiDelegate.controlValueWillStartChanging === "function")
+ this.uiDelegate.controlValueWillStartChanging(this);
+ this._valueIsChanging = true;
+ if (this.uiDelegate && typeof this.uiDelegate.controlValueDidChange === "function")
+ this.uiDelegate.controlValueDidChange(this);
+
+ this.needsLayout = true;
+ }
+
+ _handleChangeEvent()
+ {
+ delete this._valueIsChanging;
+ if (this.uiDelegate && typeof this.uiDelegate.controlValueDidStopChanging === "function")
+ this.uiDelegate.controlValueDidStopChanging(this);
+
+ this.needsLayout = true;
+ }
+
+}
+
+function addRoundedRect(ctx, x, y, width, height, radius) {
+ ctx.moveTo(x + radius, y);
+ ctx.arcTo(x + width, y, x + width, y + radius, radius);
+ ctx.lineTo(x + width, y + height - radius);
+ ctx.arcTo(x + width, y + height, x + width - radius, y + height, radius);
+ ctx.lineTo(x + radius, y + height);
+ ctx.arcTo(x, y + height, x, y + height - radius, radius);
+ ctx.lineTo(x, y + radius);
+ ctx.arcTo(x, y, x + radius, y, radius);
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/start-button.css b/Source/WebCore/Modules/modern-media-controls/controls/start-button.css
new file mode 100644
index 000000000..82e172dc4
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/start-button.css
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+button.start {
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 70px;
+ height: 70px;
+
+ background-color: transparent !important;
+
+ transform: translate3d(-50%, -50%, 0);
+}
+
+button.start > * {
+ position: absolute;
+ left: 0;
+ top: 0;
+ width: 100%;
+ height: 100%;
+}
+
+button.start > div {
+ -webkit-appearance: media-controls-light-bar-background;
+ -webkit-clip-path: circle(50%);
+ will-change: transform;
+}
+
+button.start > img {
+ opacity: 0.6;
+}
+
+button.start:active > img {
+ opacity: 1;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/start-button.js b/Source/WebCore/Modules/modern-media-controls/controls/start-button.js
new file mode 100644
index 000000000..9860c7e79
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/start-button.js
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+class StartButton extends Button
+{
+
+ constructor(layoutDelegate)
+ {
+ super(layoutDelegate);
+
+ this.element.classList.add("start");
+
+ const background = this.element.appendChild(document.createElement("div"));
+ background.className = "background";
+
+ const image = this.element.appendChild(new Image);
+ image.src = iconService.imageForIconNameAndLayoutTraits(Icons.Start, this.layoutTraits).src;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/status-label.css b/Source/WebCore/Modules/modern-media-controls/controls/status-label.css
new file mode 100644
index 000000000..a05b80bc7
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/status-label.css
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+.status-label {
+ position: absolute;
+
+ text-align: left;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ overflow: hidden;
+
+ font-size: 14px;
+
+ color: rgba(255, 255, 255, 0.572);
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/status-label.js b/Source/WebCore/Modules/modern-media-controls/controls/status-label.js
new file mode 100644
index 000000000..b39cc79dc
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/status-label.js
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+class StatusLabel extends LayoutItem
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ element: `<div class="status-label"></div>`,
+ layoutDelegate
+ });
+
+ this._text = "";
+ this._enabled = false;
+ }
+
+ // Public
+
+ get text()
+ {
+ return this._text;
+ }
+
+ set text(text)
+ {
+ if (text === this._text)
+ return;
+
+ this._text = text;
+ this.markDirtyProperty("text");
+
+ if (this.layoutDelegate)
+ this.layoutDelegate.needsLayout = true;
+ }
+
+ get enabled()
+ {
+ return this._enabled;
+ }
+
+ set enabled(enabled)
+ {
+ if (enabled === this._enabled)
+ return;
+
+ this._enabled = enabled;
+
+ if (this.layoutDelegate)
+ this.layoutDelegate.needsLayout = true;
+ }
+
+ // Protected
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "text")
+ this.element.textContent = this._text;
+ else
+ super.commitProperty(propertyName);
+ }
+
+}
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
index 000000000..ab65e22c2
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/text-tracks.css
@@ -0,0 +1,82 @@
+/*
+ * 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 {
+ 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;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/time-control.js b/Source/WebCore/Modules/modern-media-controls/controls/time-control.js
new file mode 100644
index 000000000..8a78ccd16
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/time-control.js
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+const MinimumScrubberWidth = 168;
+const ElapsedTimeLabelLeftMargin = -2;
+const ElapsedTimeLabelWidth = 40;
+const RemainingTimeLabelWidth = 49;
+const AdditionalTimeLabelWidthOverAnHour = 22;
+const ScrubberMargin = 5;
+
+class TimeControl extends LayoutItem
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ element: `<div class="time-control"></div>`,
+ layoutDelegate
+ });
+
+ this.elapsedTimeLabel = new TimeLabel;
+ this.scrubber = new Scrubber(layoutDelegate);
+ this.remainingTimeLabel = new TimeLabel;
+
+ this.children = [this.elapsedTimeLabel, this.scrubber, this.remainingTimeLabel];
+
+ this._labelsMayDisplayTimesOverAnHour = false;
+ }
+
+ // Public
+
+ get labelsMayDisplayTimesOverAnHour()
+ {
+ return this._labelsMayDisplayTimesOverAnHour;
+ }
+
+ set labelsMayDisplayTimesOverAnHour(flag)
+ {
+ if (this._labelsMayDisplayTimesOverAnHour === flag)
+ return;
+
+ this._labelsMayDisplayTimesOverAnHour = flag;
+ this.layout();
+ }
+
+ get width()
+ {
+ return super.width;
+ }
+
+ set width(width)
+ {
+ super.width = width;
+
+ const extraWidth = this._labelsMayDisplayTimesOverAnHour ? AdditionalTimeLabelWidthOverAnHour : 0;
+ const elapsedTimeLabelWidth = ElapsedTimeLabelWidth + extraWidth;
+ const remainingTimeLabelWidth = RemainingTimeLabelWidth + extraWidth;
+
+ this.elapsedTimeLabel.x = ElapsedTimeLabelLeftMargin;
+ this.elapsedTimeLabel.width = elapsedTimeLabelWidth;
+ this.scrubber.x = this.elapsedTimeLabel.x + elapsedTimeLabelWidth + ScrubberMargin;
+ this.scrubber.width = this._width - elapsedTimeLabelWidth - ScrubberMargin - remainingTimeLabelWidth;
+ this.remainingTimeLabel.x = this.scrubber.x + this.scrubber.width + ScrubberMargin;
+ }
+
+ get isSufficientlyWide()
+ {
+ return this.scrubber.width >= MinimumScrubberWidth;
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/time-label.css b/Source/WebCore/Modules/modern-media-controls/controls/time-label.css
new file mode 100644
index 000000000..76d2e91ee
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/time-label.css
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+.time-label {
+ position: absolute;
+
+ font-family: -apple-system-monospaced-numbers;
+ font-size: 14px;
+
+ text-align: right;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/time-label.js b/Source/WebCore/Modules/modern-media-controls/controls/time-label.js
new file mode 100644
index 000000000..cd0e753ab
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/time-label.js
@@ -0,0 +1,80 @@
+/*
+ * 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.
+ */
+
+class TimeLabel extends LayoutNode
+{
+
+ constructor()
+ {
+ super(`<div class="time-label"></div>`);
+
+ this.value = 0;
+ }
+
+ // Public
+
+ get value()
+ {
+ return this._value;
+ }
+
+ set value(value)
+ {
+ if (value === this._value)
+ return;
+
+ this._value = value;
+ this.markDirtyProperty("value");
+ }
+
+ // Protected
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "value")
+ this.element.textContent = this._formattedTime();
+ else
+ super.commitProperty(propertyName);
+ }
+
+ // Private
+
+ _formattedTime()
+ {
+ const time = this._value || 0;
+ const absTime = Math.abs(time);
+ const intSeconds = Math.floor(absTime % 60).toFixed(0);
+ const intMinutes = Math.floor((absTime / 60) % 60).toFixed(0);
+ const intHours = Math.floor(absTime / (60 * 60)).toFixed(0);
+
+ const timeStrings = [intMinutes, intSeconds];
+ if (intHours > 0)
+ timeStrings.unshift(intHours);
+
+ const sign = time < 0 ? "-" : "";
+ return sign + timeStrings.map(x => `00${x}`.slice(-2)).join(":");
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/tracks-button.js b/Source/WebCore/Modules/modern-media-controls/controls/tracks-button.js
new file mode 100644
index 000000000..5505f2c0b
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/tracks-button.js
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+class TracksButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "tracks",
+ iconName: Icons.Tracks,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css b/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css
new file mode 100644
index 000000000..b0717483f
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.css
@@ -0,0 +1,105 @@
+/*
+ * 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.
+ */
+
+.tracks-panel {
+ position: absolute;
+ display: inline-block;
+}
+
+.tracks-panel > .background-tint > div {
+ border-radius: 7px;
+}
+
+.tracks-panel * {
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.tracks-panel.fade-out {
+ transition-property: opacity;
+ transition-duration: 265ms;
+ opacity: 0;
+}
+
+.tracks-panel > section {
+ border-top: 2px solid rgb(104, 104, 104);
+ will-change: transform;
+}
+
+.tracks-panel > section:first-of-type {
+ border-top: 0;
+}
+
+.tracks-panel > section > h3 {
+ color: rgb(150, 150, 150);
+ padding: 5px 20px 1px 21px;
+ margin: 0;
+}
+
+.tracks-panel > section > ul {
+ list-style-type: none;
+ margin-top: 0;
+ padding: 0;
+}
+
+.tracks-panel > section > ul > li {
+ position: relative;
+ padding: 1px 20px 1px 33px;
+ color: white;
+}
+
+.tracks-panel > section > ul > li:focus {
+ background-color: rgba(26, 68, 243, 0.6);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+ outline: none;
+}
+
+.tracks-panel > section > ul > li.selected:before {
+ position: absolute;
+ top: 3px;
+ left: 12px;
+ width: 12px;
+ display: inline-block;
+ content: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 300 300"><polygon fill="white" points="252.301,4.477 126.667,194.104 43.358,108.3 6.868,161.408 132.515,290.814 297.732,49.926"/></svg>');
+}
+
+.tracks-panel > section > ul > li.animated {
+ animation-name: tracks-panel-item-selection;
+ animation-duration: 150ms;
+ animation-timing-function: step-end;
+ animation-fill-mode: forwards;
+}
+
+@keyframes tracks-panel-item-selection {
+ 0%, 55.55% {
+ background-color: rgba(26, 68, 243, 0.6);
+ -webkit-backdrop-filter: saturate(180%) blur(20px);
+ }
+
+ 22.22% {
+ background: none;
+ -webkit-backdrop-filter: none;
+ }
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js b/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js
new file mode 100644
index 000000000..4a69bb6e2
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/tracks-panel.js
@@ -0,0 +1,305 @@
+
+class TracksPanel extends LayoutNode
+{
+
+ constructor()
+ {
+ super(`<div class="tracks-panel"></div>`);
+ this._backgroundTint = new BackgroundTint;
+ this._rightX = 0;
+ this._bottomY = 0;
+ }
+
+ // Public
+
+ get presented()
+ {
+ return !!this.parent;
+ }
+
+ presentInParent(node)
+ {
+ if (this.parent === node)
+ return;
+
+ this.children = this._childrenFromDataSource();
+
+ node.addChild(this);
+
+ this.element.removeEventListener("transitionend", this);
+ this.element.classList.remove("fade-out");
+
+ this._mousedownTarget().addEventListener("mousedown", this, true);
+ window.addEventListener("keydown", this, true);
+
+ this._focusedTrackNode = null;
+ }
+
+ hide()
+ {
+ if (!this.presented)
+ return;
+
+ this._mousedownTarget().removeEventListener("mousedown", this, true);
+ window.removeEventListener("keydown", this, true);
+
+ this.element.addEventListener("transitionend", this);
+
+ // Ensure a transition will indeed happen by starting it only on the next frame.
+ window.requestAnimationFrame(() => { this.element.classList.add("fade-out"); });
+ }
+
+ get bottomY()
+ {
+ return this._bottomY;
+ }
+
+ set bottomY(bottomY)
+ {
+ if (this._bottomY === bottomY)
+ return;
+
+ this._bottomY = bottomY;
+ this.markDirtyProperty("bottomY");
+ }
+
+ get rightX()
+ {
+ return this._rightX;
+ }
+
+ set rightX(x)
+ {
+ if (this._rightX === x)
+ return;
+
+ this._rightX = x;
+ this.markDirtyProperty("rightX");
+ }
+
+ // Protected
+
+ trackNodeSelectionAnimationDidEnd(trackNode)
+ {
+ if (this.uiDelegate && typeof this.uiDelegate.tracksPanelSelectionDidChange === "function")
+ this.uiDelegate.tracksPanelSelectionDidChange(trackNode.index, trackNode.sectionIndex);
+ }
+
+ mouseMovedOverTrackNode(trackNode)
+ {
+ this._focusTrackNode(trackNode);
+ }
+
+ mouseExitedTrackNode(trackNode)
+ {
+ this._focusedTrackNode.element.blur();
+ delete this._focusedTrackNode;
+ }
+
+ commitProperty(propertyName)
+ {
+ if (propertyName === "rightX")
+ this.element.style.right = `${this._rightX}px`;
+ else if (propertyName === "bottomY")
+ this.element.style.bottom = `${this._bottomY}px`;
+ else
+ super.commitProperty(propertyName);
+ }
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "mousedown":
+ this._handleMousedown(event);
+ break;
+ case "keydown":
+ this._handleKeydown(event);
+ break;
+ case "transitionend":
+ this.remove();
+ break;
+ }
+ }
+
+ // Private
+
+ _mousedownTarget()
+ {
+ const mediaControls = this.parentOfType(MacOSFullscreenMediaControls);
+ if (mediaControls)
+ return mediaControls.element;
+ return window;
+ }
+
+ _childrenFromDataSource()
+ {
+ const children = [this._backgroundTint];
+
+ this._trackNodes = [];
+
+ const dataSource = this.dataSource;
+ if (!dataSource)
+ return children;
+
+ const numberOfSections = dataSource.tracksPanelNumberOfSections();
+ if (numberOfSections === 0)
+ return children;
+
+ for (let sectionIndex = 0; sectionIndex < numberOfSections; ++sectionIndex) {
+ let sectionNode = new LayoutNode(`<section></section>`);
+ sectionNode.addChild(new LayoutNode(`<h3>${dataSource.tracksPanelTitleForSection(sectionIndex)}</h3>`));
+
+ let tracksListNode = sectionNode.addChild(new LayoutNode(`<ul></ul>`));
+ let numberOfTracks = dataSource.tracksPanelNumberOfTracksInSection(sectionIndex);
+ for (let trackIndex = 0; trackIndex < numberOfTracks; ++trackIndex) {
+ let trackTitle = dataSource.tracksPanelTitleForTrackInSection(trackIndex, sectionIndex);
+ let trackSelected = dataSource.tracksPanelIsTrackInSectionSelected(trackIndex, sectionIndex);
+ let trackNode = tracksListNode.addChild(new TrackNode(trackIndex, sectionIndex, trackTitle, trackSelected, this));
+ this._trackNodes.push(trackNode);
+ }
+ children.push(sectionNode);
+ }
+
+ return children;
+ }
+
+ _handleMousedown(event)
+ {
+ if (this.element.contains(event.target))
+ return;
+
+ this._dismiss();
+
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ _handleKeydown(event)
+ {
+ switch (event.key) {
+ case "Home":
+ case "PageUp":
+ this._focusFirstTrackNode();
+ break;
+ case "End":
+ case "PageDown":
+ this._focusLastTrackNode();
+ break;
+ case "ArrowDown":
+ if (event.altKey || event.metaKey)
+ this._focusLastTrackNode();
+ else
+ this._focusNextTrackNode();
+ break;
+ case "ArrowUp":
+ if (event.altKey || event.metaKey)
+ this._focusFirstTrackNode();
+ else
+ this._focusPreviousTrackNode();
+ break;
+ case " ":
+ case "Enter":
+ if (this._focusedTrackNode)
+ this._focusedTrackNode.activate();
+ break;
+ case "Escape":
+ this._dismiss();
+ break;
+ }
+ }
+
+ _dismiss()
+ {
+ if (this.parent && typeof this.parent.hideTracksPanel === "function")
+ this.parent.hideTracksPanel();
+ }
+
+ _focusTrackNode(trackNode)
+ {
+ if (!trackNode || trackNode === this._focusedTrackNode)
+ return;
+
+ trackNode.element.focus();
+ this._focusedTrackNode = trackNode;
+ }
+
+ _focusPreviousTrackNode()
+ {
+ const previousIndex = this._focusedTrackNode ? this._trackNodes.indexOf(this._focusedTrackNode) - 1 : this._trackNodes.length - 1;
+ this._focusTrackNode(this._trackNodes[previousIndex]);
+ }
+
+ _focusNextTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[this._trackNodes.indexOf(this._focusedTrackNode) + 1]);
+ }
+
+ _focusFirstTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[0]);
+ }
+
+ _focusLastTrackNode()
+ {
+ this._focusTrackNode(this._trackNodes[this._trackNodes.length - 1]);
+ }
+
+}
+
+class TrackNode extends LayoutNode
+{
+
+ constructor(index, sectionIndex, title, selected, panel)
+ {
+ super(`<li tabindex="0">${title}</li>`);
+
+ this.index = index;
+ this.sectionIndex = sectionIndex;
+ this._panel = panel;
+ this._selected = selected;
+
+ if (selected)
+ this.element.classList.add("selected");
+
+ this.element.addEventListener("mousemove", this);
+ this.element.addEventListener("mouseleave", this);
+ this.element.addEventListener("click", this);
+ }
+
+ // Public
+
+ activate()
+ {
+ this.element.addEventListener("animationend", this);
+ this.element.classList.add("animated");
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ switch (event.type) {
+ case "mousemove":
+ this._panel.mouseMovedOverTrackNode(this);
+ break;
+ case "mouseleave":
+ this._panel.mouseExitedTrackNode(this);
+ break;
+ case "click":
+ this.activate();
+ break;
+ case "animationend":
+ this._animationDidEnd();
+ break;
+ }
+ }
+
+ // Private
+
+ _animationDidEnd()
+ {
+ this.element.removeEventListener("animationend", this);
+ this._panel.trackNodeSelectionAnimationDidEnd(this);
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/volume-down-button.js b/Source/WebCore/Modules/modern-media-controls/controls/volume-down-button.js
new file mode 100644
index 000000000..b5c9d1daf
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/volume-down-button.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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 VolumeDownButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "volume-down",
+ iconName: Icons.VolumeDown,
+ layoutDelegate
+ });
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.css b/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.css
new file mode 100644
index 000000000..42b904bd6
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.css
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+.volume.slider > input::-webkit-slider-thumb {
+ width: 11px;
+ height: 11px;
+ border-radius: 5.5px;
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.js b/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.js
new file mode 100644
index 000000000..993eb16f1
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/volume-slider.js
@@ -0,0 +1,120 @@
+/*
+ * 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.
+ */
+
+class VolumeSlider extends Slider
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "volume",
+ layoutDelegate
+ });
+
+ this.height = 11;
+ this.enabled = true;
+
+ this._active = false;
+ this.element.addEventListener("mousedown", this);
+ }
+
+ // Protected
+
+ handleEvent(event)
+ {
+ super.handleEvent(event);
+
+ if (event instanceof MouseEvent) {
+ this._active = event.type === "mousedown";
+ if (event.type === "mousedown")
+ window.addEventListener("mouseup", this, true);
+ else
+ window.removeEventListener("mouseup", this, true);
+ }
+ }
+
+ draw(ctx)
+ {
+ const width = this.width;
+ const height = this.height;
+
+ if (!this.width || !this.height)
+ return;
+
+ const dpr = window.devicePixelRatio;
+
+ ctx.save();
+ ctx.scale(dpr, dpr);
+ ctx.clearRect(0, 0, width, height);
+
+ const trackHeight = 3;
+ const knobRadius = 5.5;
+ const knobDiameter = 2 * knobRadius;
+ const borderSize = 2;
+ const knobX = Math.round(this.value * (width - knobDiameter - borderSize));
+
+ // Draw portion of volume under slider thumb.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, 0, 4, knobX + 2, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(84, 84, 84)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+
+ // Draw portion of volume above slider thumb.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, knobX, 4, width - knobX, trackHeight, trackHeight / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = "rgb(39, 39, 39)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+
+ // Clear a hole in the slider for the scrubber.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, knobX, 0, knobDiameter + borderSize, height, (knobDiameter + borderSize) / 2);
+ ctx.closePath();
+ ctx.clip();
+ ctx.clearRect(0, 0, width, height);
+ ctx.restore();
+
+ // Draw scrubber.
+ ctx.save();
+ ctx.beginPath();
+ addRoundedRect(ctx, knobX + 1, 0, knobDiameter, knobDiameter, knobRadius);
+ ctx.closePath();
+ ctx.clip();
+ ctx.fillStyle = this._active ? "white" : "rgb(138, 138, 138)";
+ ctx.fillRect(0, 0, width, height);
+ ctx.restore();
+
+ ctx.restore();
+ }
+
+}
diff --git a/Source/WebCore/Modules/modern-media-controls/controls/volume-up-button.js b/Source/WebCore/Modules/modern-media-controls/controls/volume-up-button.js
new file mode 100644
index 000000000..8d9432436
--- /dev/null
+++ b/Source/WebCore/Modules/modern-media-controls/controls/volume-up-button.js
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2017 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 VolumeUpButton extends IconButton
+{
+
+ constructor(layoutDelegate)
+ {
+ super({
+ cssClassName: "volume-up",
+ iconName: Icons.VolumeUp,
+ layoutDelegate
+ });
+ }
+
+}