Source/WebCore/ChangeLog

 12021-09-23 Antoine Quint <graouts@webkit.org>
 2
 3 [Media Controls] Allow for a single mute and volume button
 4 https://bugs.webkit.org/show_bug.cgi?id=230692
 5 <rdar://problem/79956248>
 6
 7 Reviewed by NOBODY (OOPS!).
 8
 9 Up to now, the mute button in the controls bar would act as a toggle for the "muted" property on the media element.
 10 Hovering that button would make a slider appear that would allow the "volume" property of the media element to be
 11 changed as well.
 12
 13 We now allow for a single button with a built-in range indicator to be used for mute and volume. Clicking on the
 14 button without moving will toggle the mute status, while moving the mouse up or down will adjust the volume
 15 and show a pill-link range indicator showing the current volume.
 16
 17 This new control is a Button subclass called RangeButton. The new VolumeButton class extends it to provide the
 18 correct icon depending on the volume and muted state. The new MuteAndVolumeSupport class is used in conjunction
 19 with VolumeButton.
 20
 21 To indicate that media controls want to use this new style, MediaControls subclasses can override the
 22 usesSingleMuteAndVolumeButton getter to return true. Currently it's false everywhere until we decide
 23 to use this style.
 24
 25 * DerivedSources-input.xcfilelist:
 26 * DerivedSources.make:
 27 * Modules/modern-media-controls/controls/media-controls.js:
 28 (MediaControls.prototype.get usesSingleMuteAndVolumeButton):
 29 * Modules/modern-media-controls/controls/range-button.css: Added.
 30 (button.range > div.indicator):
 31 (button.range > div.indicator > div.fill):
 32 * Modules/modern-media-controls/controls/range-button.js: Added.
 33 (RangeButton.prototype.get value):
 34 (RangeButton.prototype.set value):
 35 (RangeButton.prototype.commitProperty):
 36 (RangeButton.prototype.handleEvent):
 37 (RangeButton.prototype._handlePointerdown):
 38 (RangeButton.prototype._handlePointermove):
 39 (RangeButton.prototype._handlePointerup):
 40 * Modules/modern-media-controls/controls/volume-button.js: Added.
 41 (VolumeButton):
 42 (VolumeButton.prototype.get volume):
 43 (VolumeButton.prototype.set volume):
 44 (VolumeButton.prototype.get muted):
 45 (VolumeButton.prototype.set muted):
 46 (VolumeButton.prototype.set usesLTRUserInterfaceLayoutDirection):
 47 (VolumeButton.prototype.layout):
 48 * Modules/modern-media-controls/js-files:
 49 * Modules/modern-media-controls/media/media-controller.js:
 50 (MediaController.prototype._supportingObjectClasses):
 51 * Modules/modern-media-controls/media/mute-and-volume-support.js: Added.
 52 (MuteAndVolumeSupport.prototype.get control):
 53 (MuteAndVolumeSupport.prototype.get mediaEvents):
 54 (MuteAndVolumeSupport.prototype.controlValueWillStartChanging):
 55 (MuteAndVolumeSupport.prototype.controlValueDidChange):
 56 (MuteAndVolumeSupport.prototype.controlValueDidStopChanging):
 57 (MuteAndVolumeSupport.prototype.buttonWasPressed):
 58 (MuteAndVolumeSupport.prototype.syncControl):
 59 (MuteAndVolumeSupport):
 60 * WebCore.xcodeproj/project.pbxproj:
 61
1622021-09-19 Simon Fraser <simon.fraser@apple.com>
263
364 Have ScrollAnimation work in terms of offsets, not positions

Source/WebCore/DerivedSources-input.xcfilelist

@@$(PROJECT_DIR)/Modules/modern-media-controls/controls/pip-placard.js
327327$(PROJECT_DIR)/Modules/modern-media-controls/controls/placard.css
328328$(PROJECT_DIR)/Modules/modern-media-controls/controls/placard.js
329329$(PROJECT_DIR)/Modules/modern-media-controls/controls/play-pause-button.js
 330$(PROJECT_DIR)/Modules/modern-media-controls/controls/range-button.css
 331$(PROJECT_DIR)/Modules/modern-media-controls/controls/range-button.js
330332$(PROJECT_DIR)/Modules/modern-media-controls/controls/rewind-button.js
331333$(PROJECT_DIR)/Modules/modern-media-controls/controls/scheduler.js
332334$(PROJECT_DIR)/Modules/modern-media-controls/controls/seek-button.js

@@$(PROJECT_DIR)/Modules/modern-media-controls/controls/time-control.js
341343$(PROJECT_DIR)/Modules/modern-media-controls/controls/time-label.css
342344$(PROJECT_DIR)/Modules/modern-media-controls/controls/time-label.js
343345$(PROJECT_DIR)/Modules/modern-media-controls/controls/tracks-button.js
 346$(PROJECT_DIR)/Modules/modern-media-controls/controls/volume-button.js
344347$(PROJECT_DIR)/Modules/modern-media-controls/controls/watchos-activity-indicator.css
345348$(PROJECT_DIR)/Modules/modern-media-controls/controls/watchos-activity-indicator.js
346349$(PROJECT_DIR)/Modules/modern-media-controls/controls/watchos-layout-traits.js

@@$(PROJECT_DIR)/Modules/modern-media-controls/media/fullscreen-support.js
357360$(PROJECT_DIR)/Modules/modern-media-controls/media/media-controller-support.js
358361$(PROJECT_DIR)/Modules/modern-media-controls/media/media-controller.js
359362$(PROJECT_DIR)/Modules/modern-media-controls/media/media-document-controller.js
 363$(PROJECT_DIR)/Modules/modern-media-controls/media/mute-and-volume-support.js
360364$(PROJECT_DIR)/Modules/modern-media-controls/media/mute-support.js
361365$(PROJECT_DIR)/Modules/modern-media-controls/media/overflow-support.js
362366$(PROJECT_DIR)/Modules/modern-media-controls/media/pip-support.js

Source/WebCore/DerivedSources.make

@@MODERN_MEDIA_CONTROLS_STYLE_SHEETS = \
15481548 $(WebCore)/Modules/modern-media-controls/controls/media-controls.css \
15491549 $(WebCore)/Modules/modern-media-controls/controls/media-document.css \
15501550 $(WebCore)/Modules/modern-media-controls/controls/placard.css \
 1551 $(WebCore)/Modules/modern-media-controls/controls/range-button.css \
15511552 $(WebCore)/Modules/modern-media-controls/controls/slider.css \
15521553 $(WebCore)/Modules/modern-media-controls/controls/status-label.css \
15531554 $(WebCore)/Modules/modern-media-controls/controls/text-tracks.css \

@@MODERN_MEDIA_CONTROLS_SCRIPTS = \
16231624 $(WebCore)/Modules/modern-media-controls/controls/rewind-button.js \
16241625 $(WebCore)/Modules/modern-media-controls/controls/forward-button.js \
16251626 $(WebCore)/Modules/modern-media-controls/controls/overflow-button.js \
 1627 $(WebCore)/Modules/modern-media-controls/controls/range-button.js \
 1628 $(WebCore)/Modules/modern-media-controls/controls/volume-button.js \
16261629 $(WebCore)/Modules/modern-media-controls/controls/buttons-container.js \
16271630 $(WebCore)/Modules/modern-media-controls/controls/status-label.js \
16281631 $(WebCore)/Modules/modern-media-controls/controls/controls-bar.js \

@@MODERN_MEDIA_CONTROLS_SCRIPTS = \
16631666 $(WebCore)/Modules/modern-media-controls/media/time-control-support.js \
16641667 $(WebCore)/Modules/modern-media-controls/media/tracks-support.js \
16651668 $(WebCore)/Modules/modern-media-controls/media/volume-support.js \
 1669 $(WebCore)/Modules/modern-media-controls/media/mute-and-volume-support.js \
16661670 $(WebCore)/Modules/modern-media-controls/media/media-document-controller.js \
16671671 $(WebCore)/Modules/modern-media-controls/media/watchos-media-controls-support.js \
16681672 $(WebCore)/Modules/modern-media-controls/media/media-controller.js \

Source/WebCore/Modules/modern-media-controls/controls/media-controls.js

@@class MediaControls extends LayoutNode
4444 this.muteButton = new MuteButton(this);
4545 this.tracksButton = new TracksButton(this);
4646 this.overflowButton = new OverflowButton(this);
 47 this.volumeButton = new VolumeButton(this);
4748
4849 this.statusLabel = new StatusLabel(this);
4950 this.timeControl = new TimeControl(this);

@@class MediaControls extends LayoutNode
235236 super.commitProperty(propertyName);
236237 }
237238
 239 get usesSingleMuteAndVolumeButton()
 240 {
 241 return false;
 242 }
238243}

Source/WebCore/Modules/modern-media-controls/controls/range-button.css

 1/*
 2 * Copyright (C) 2021 Apple Inc. All Rights Reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26button.range > div.indicator {
 27 --indicator-width: 45px;
 28 --indicator-height: 134px;
 29
 30 position: absolute;
 31 top: calc(100% - var(--indicator-height) - 5px);
 32 width: var(--indicator-width);
 33 height: var(--indicator-height);
 34
 35 clip-path: path('M0,22.5 a22.5,22.5 0 0 1 45,0 v89 a22.5,22.5 0 0 1 -45,0 z');
 36}
 37
 38button.range > div.indicator > div.fill {
 39 position: absolute;
 40 left: 0;
 41 bottom: 0;
 42 width: 100%;
 43 height: 0;
 44 background-color: rgba(255, 255, 255, 0.5);
 45}

Source/WebCore/Modules/modern-media-controls/controls/range-button.js

 1/*
 2 * Copyright (C) 2021 Apple Inc. All Rights Reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26class RangeButton extends Button
 27{
 28
 29 constructor({ layoutDelegate = null, cssClassName = "", iconName = "" } = {})
 30 {
 31 super({ layoutDelegate, cssClassName, iconName });
 32
 33 this._value = 0;
 34
 35 this.element.classList.add("range");
 36 this.element.addEventListener("pointerdown", this);
 37
 38 this._indicator = this.addChild(new LayoutNode(`<div class="indicator"></div>`), 0);
 39 this._indicatorTint = this._indicator.addChild(new BackgroundTint);
 40 this._indicatorFill = this._indicator.addChild(new LayoutNode(`<div class="fill"></div>`));
 41
 42 this._indicator.visible = false;
 43
 44 if (GestureRecognizer.SupportsTouches)
 45 this._tapGestureRecognizer.enabled = false;
 46 else
 47 this.element.removeEventListener("click", this);
 48 }
 49
 50 // Public
 51
 52 get value()
 53 {
 54 return this._value;
 55 }
 56
 57 set value(value)
 58 {
 59 this._value = value;
 60 this.markDirtyProperty("value");
 61 }
 62
 63 // Protected
 64
 65 commitProperty(propertyName)
 66 {
 67 if (propertyName === "value")
 68 this._indicatorFill.element.style.height = `${this._value * 100}%`;
 69 else
 70 super.commitProperty(propertyName);
 71 }
 72
 73 handleEvent(event)
 74 {
 75 if (event.currentTarget === this.element && event.type == "pointerdown")
 76 this._handlePointerdown(event);
 77 else if (event.currentTarget === window && event.type === "pointermove")
 78 this._handlePointermove(event);
 79 else if (event.currentTarget === window && event.type === "pointerup")
 80 this._handlePointerup(event);
 81 else
 82 super.handleEvent(event);
 83 }
 84
 85 // Private
 86
 87 _handlePointerdown(event)
 88 {
 89 window.addEventListener("pointermove", this, true);
 90 window.addEventListener("pointerup", this, true);
 91
 92 this._initialPointerY = event.clientY;
 93 this._initialValue = this._value;
 94 }
 95
 96 _handlePointermove(event)
 97 {
 98 if (!this._indicator.visible) {
 99 this._indicator.visible = true;
 100 if (this.uiDelegate && typeof this.uiDelegate.controlValueWillStartChanging === "function")
 101 this.uiDelegate.controlValueWillStartChanging(this);
 102 return;
 103 }
 104
 105 if (!this._indicatorHeight)
 106 this._indicatorHeight = this._indicator.computedValueForStylePropertyInPx("height");
 107
 108 if (!this._indicatorHeight)
 109 return;
 110
 111 const traveledPointerDistance = this._initialPointerY - event.clientY;
 112 const valueIncrement = traveledPointerDistance / this._indicatorHeight;
 113
 114 const newValue = Math.max(0, Math.min(1, this._initialValue + valueIncrement));
 115 if (this._value === newValue)
 116 return;
 117
 118 this.value = newValue;
 119
 120 if (this.uiDelegate && typeof this.uiDelegate.controlValueDidChange === "function")
 121 this.uiDelegate.controlValueDidChange(this);
 122 }
 123
 124 _handlePointerup(event)
 125 {
 126 window.removeEventListener("pointermove", this, true);
 127 window.removeEventListener("pointerup", this, true);
 128
 129 delete this._initialPointerY;
 130 delete this._initialValue;
 131
 132 if (this._indicator.visible) {
 133 if (this.uiDelegate && typeof this.uiDelegate.controlValueDidStopChanging === "function")
 134 this.uiDelegate.controlValueDidStopChanging(this);
 135 this._indicator.visible = false;
 136 } else {
 137 if (this._enabled && this.uiDelegate && typeof this.uiDelegate.buttonWasPressed === "function")
 138 this.uiDelegate.buttonWasPressed(this);
 139 }
 140 }
 141
 142}

Source/WebCore/Modules/modern-media-controls/controls/volume-button.js

 1/*
 2 * Copyright (C) 2021 Apple Inc. All Rights Reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26class VolumeButton extends RangeButton
 27{
 28
 29 constructor(layoutDelegate)
 30 {
 31 super({
 32 cssClassName: "mute",
 33 iconName: Icons.VolumeMutedRTL,
 34 layoutDelegate
 35 });
 36
 37 this._muted = true;
 38
 39 this._usesLTRUserInterfaceLayoutDirection = undefined;
 40 }
 41
 42 // Public
 43
 44 get volume()
 45 {
 46 return this.value;
 47 }
 48
 49 set volume(volume)
 50 {
 51 this.value = volume;
 52 this.needsLayout = true;
 53 }
 54
 55 get muted()
 56 {
 57 return this._muted;
 58 }
 59
 60 set muted(flag)
 61 {
 62 if (this._muted === flag)
 63 return;
 64
 65 this._muted = flag;
 66 this.needsLayout = true;
 67 }
 68
 69 set usesLTRUserInterfaceLayoutDirection(usesLTRUserInterfaceLayoutDirection)
 70 {
 71 if (usesLTRUserInterfaceLayoutDirection === this._usesLTRUserInterfaceLayoutDirection)
 72 return;
 73
 74 this._usesLTRUserInterfaceLayoutDirection = usesLTRUserInterfaceLayoutDirection;
 75
 76 this.needsLayout = true;
 77 }
 78
 79 // Protected
 80
 81 layout()
 82 {
 83 if (this._muted || this.volume < 0)
 84 this.iconName = this._usesLTRUserInterfaceLayoutDirection ? Icons.VolumeMuted : Icons.VolumeMutedRTL;
 85 else if (this.volume < 0.25)
 86 this.iconName = this._usesLTRUserInterfaceLayoutDirection ? Icons.Volume0 : Icons.Volume0RTL;
 87 else if (this.volume < 0.5)
 88 this.iconName = this._usesLTRUserInterfaceLayoutDirection ? Icons.Volume1 : Icons.Volume1RTL;
 89 else if (this.volume < 0.75)
 90 this.iconName = this._usesLTRUserInterfaceLayoutDirection ? Icons.Volume2 : Icons.Volume2RTL;
 91 else
 92 this.iconName = this._usesLTRUserInterfaceLayoutDirection ? Icons.Volume3 : Icons.Volume3RTL;
 93 }
 94}

Source/WebCore/Modules/modern-media-controls/js-files

@@controls/seek-button.js
2424controls/rewind-button.js
2525controls/forward-button.js
2626controls/overflow-button.js
 27controls/range-button.js
 28controls/volume-button.js
2729controls/buttons-container.js
2830controls/status-label.js
2931controls/controls-bar.js

@@media/airplay-support.js
4850media/audio-support.js
4951media/controls-visibility-support.js
5052media/fullscreen-support.js
 53media/mute-and-volume-support.js
5154media/mute-support.js
5255media/overflow-support.js
5356media/pip-support.js

Source/WebCore/Modules/modern-media-controls/media/media-controller.js

@@class MediaController
213213 if (overridenSupportingObjectClasses)
214214 return overridenSupportingObjectClasses;
215215
216  return [AirplaySupport, AudioSupport, ControlsVisibilitySupport, FullscreenSupport, MuteSupport, OverflowSupport, PiPSupport, PlacardSupport, PlaybackSupport, ScrubbingSupport, SeekBackwardSupport, SeekForwardSupport, SkipBackSupport, SkipForwardSupport, StartSupport, StatusSupport, TimeControlSupport, TracksSupport, VolumeSupport];
 216 let classes = [AirplaySupport, AudioSupport, ControlsVisibilitySupport, FullscreenSupport, OverflowSupport, PiPSupport, PlacardSupport, PlaybackSupport, ScrubbingSupport, SeekBackwardSupport, SeekForwardSupport, SkipBackSupport, SkipForwardSupport, StartSupport, StatusSupport, TimeControlSupport, TracksSupport]
 217
 218 if (this.controls.usesSingleMuteAndVolumeButton)
 219 classes.push(MuteAndVolumeSupport);
 220 else
 221 classes.push(MuteSupport, VolumeSupport);
 222
 223 return classes;
217224 }
218225
219226 _updateControlsIfNeeded()

Source/WebCore/Modules/modern-media-controls/media/mute-and-volume-support.js

 1/*
 2 * Copyright (C) 2021 Apple Inc. All Rights Reserved.
 3 *
 4 * Redistribution and use in source and binary forms, with or without
 5 * modification, are permitted provided that the following conditions
 6 * are met:
 7 * 1. Redistributions of source code must retain the above copyright
 8 * notice, this list of conditions and the following disclaimer.
 9 * 2. Redistributions in binary form must reproduce the above copyright
 10 * notice, this list of conditions and the following disclaimer in the
 11 * documentation and/or other materials provided with the distribution.
 12 *
 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 24 */
 25
 26class MuteAndVolumeSupport extends MediaControllerSupport
 27{
 28
 29 // Protected
 30
 31 get control()
 32 {
 33 return this.mediaController.controls.volumeButton;
 34 }
 35
 36 get mediaEvents()
 37 {
 38 return ["volumechange"];
 39 }
 40
 41 controlValueWillStartChanging(control)
 42 {
 43 this._volumeBeforeChange = this.mediaController.media.volume;
 44 this.mediaController.controls.autoHideController.hasSecondaryUIAttached = true;
 45 }
 46
 47 controlValueDidChange(control)
 48 {
 49 this.mediaController.media.volume = (control.value === 0 && this._volumeBeforeChange > 0) ? this._volumeBeforeChange : control.value;
 50 this.mediaController.media.muted = control.value === 0;
 51 }
 52
 53 controlValueDidStopChanging(control)
 54 {
 55 delete this._volumeBeforeChange;
 56 this.mediaController.controls.autoHideController.hasSecondaryUIAttached = false;
 57 }
 58
 59 buttonWasPressed(control)
 60 {
 61 const media = this.mediaController.media;
 62 media.muted = !media.muted;
 63 }
 64
 65 syncControl()
 66 {
 67 const media = this.mediaController.media;
 68 this.control.volume = this.mediaController.media.volume;
 69 this.control.muted = this.mediaController.media.muted;
 70 }
 71
 72}

Source/WebCore/WebCore.xcodeproj/project.pbxproj

1036510365 715AD71D2050512400D592DC /* DeclarativeAnimation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DeclarativeAnimation.h; sourceTree = "<group>"; };
1036610366 715AD71F2050512400D592DC /* DeclarativeAnimation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DeclarativeAnimation.cpp; sourceTree = "<group>"; };
1036710367 715DA5D3201BB902002EF2B0 /* JSWebAnimationCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWebAnimationCustom.cpp; sourceTree = "<group>"; };
 10368 716A55AB26FA349B00C96D69 /* range-button.css */ = {isa = PBXFileReference; lastKnownFileType = text.css; path = "range-button.css"; sourceTree = "<group>"; };
 10369 716A55AD26FA349C00C96D69 /* volume-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "volume-button.js"; sourceTree = "<group>"; };
 10370 716A55AE26FA349C00C96D69 /* range-button.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "range-button.js"; sourceTree = "<group>"; };
1036810371 716FA0D81DB26591007323CC /* airplay-button.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = "airplay-button.css"; sourceTree = "<group>"; };
1036910372 716FA0D91DB26591007323CC /* airplay-button.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "airplay-button.js"; sourceTree = "<group>"; };
1037010373 716FA0DA1DB26591007323CC /* airplay-placard.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "airplay-placard.js"; sourceTree = "<group>"; };

1045810461 71D6AA931DA4EAF700B23969 /* airplay-placard@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "airplay-placard@2x.png"; sourceTree = "<group>"; };
1045910462 71D6AAAA1DA4EAF700B23969 /* pip-placard@1x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pip-placard@1x.png"; sourceTree = "<group>"; };
1046010463 71D6AAAB1DA4EAF700B23969 /* pip-placard@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "pip-placard@2x.png"; sourceTree = "<group>"; };
 10464 71D8323126FCD8F600F348A4 /* mute-and-volume-support.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "mute-and-volume-support.js"; sourceTree = "<group>"; };
 10465 71D8323326FCD8F600F348A4 /* skip-forward-support.js */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.javascript; path = "skip-forward-support.js"; sourceTree = "<group>"; };
1046110466 71DCB6FF1568197600862271 /* JSSVGZoomAndPan.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSSVGZoomAndPan.cpp; sourceTree = "<group>"; };
1046210467 71DCB7001568197600862271 /* JSSVGZoomAndPan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSSVGZoomAndPan.h; sourceTree = "<group>"; };
1046310468 71DE2794203A9C1C0058CB51 /* watchos-media-controls.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = "watchos-media-controls.js"; sourceTree = "<group>"; };

2283922844 716FA0EF1DB26591007323CC /* placard.css */,
2284022845 716FA0F01DB26591007323CC /* placard.js */,
2284122846 716FA0F11DB26591007323CC /* play-pause-button.js */,
 22847 716A55AB26FA349B00C96D69 /* range-button.css */,
 22848 716A55AE26FA349C00C96D69 /* range-button.js */,
2284222849 716FA0F21DB26591007323CC /* rewind-button.js */,
2284322850 716FA0F31DB26591007323CC /* scheduler.js */,
2284422851 718675431DF101AD0033D7F3 /* seek-button.js */,

2285322860 716FA0FC1DB26591007323CC /* time-label.css */,
2285422861 716FA0FD1DB26591007323CC /* time-label.js */,
2285522862 716FA0FE1DB26591007323CC /* tracks-button.js */,
 22863 716A55AD26FA349C00C96D69 /* volume-button.js */,
2285622864 9551958E25FA9E3000F58CF0 /* watchos-activity-indicator.css */,
2285722865 9551958F25FA9E3100F58CF0 /* watchos-activity-indicator.js */,
2285822866 BCD3736F26864203003644E4 /* watchos-layout-traits.js */,

2287322881 7177E2461DB80D2F00919A0B /* media-controller-support.js */,
2287422882 71D02D921DB55C4E00DD5CF5 /* media-controller.js */,
2287522883 9551959225FA9E4C00F58CF0 /* media-document-controller.js */,
 22884 71D8323126FCD8F600F348A4 /* mute-and-volume-support.js */,
2287622885 7177E2471DB80D2F00919A0B /* mute-support.js */,
2287722886 950C484925D6774200AB3D9C /* overflow-support.js */,
2287822887 7130141D1DC9C08600CA3A88 /* pip-support.js */,

2288322892 718675451DF101C60033D7F3 /* seek-forward-support.js */,
2288422893 718675461DF101C60033D7F3 /* seek-support.js */,
2288522894 71D2554F1DB900020004D76B /* skip-back-support.js */,
 22895 71D8323326FCD8F600F348A4 /* skip-forward-support.js */,
2288622896 7177E2481DB80D2F00919A0B /* start-support.js */,
2288722897 71B0460A1DD3C2EE00EE19CF /* status-support.js */,
2288822898 9551959525FA9E7E00F58CF0 /* time-control-support.js */,