[MediaControls] Refactor media controls & bring improvements made to iOS controls...
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 May 2015 21:30:18 +0000 (21:30 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 15 May 2015 21:30:18 +0000 (21:30 +0000)
https://bugs.webkit.org/show_bug.cgi?id=144973

Reviewed by Dean Jackson.

Pull improvements made to the iOS media controls back into the Mac controls by moving
code from mediaControlsiOS.js into MediaControlsApple.js.

The largest refactored feature is the ability to drop individual controls from the media
controls when the video is too small to contain them. To allow these controls to resize
dynamically, a new "resize" event is fired inside the media element's shadow DOM.

* Modules/mediacontrols/mediaControlsApple.css:
(audio::-webkit-media-controls-panel .dropped): Added; sets "display: none".
* Modules/mediacontrols/mediaControlsApple.js:
(Controller): Set defaults for new variables.
(Controller.prototype.updateControls): Update the controls width; moved from iOS.js.
(Controller.prototype.handleReadyStateChange): Update the controls; moved from iOS.js.
(Controller.prototype.handleTimeUpdate): Update the progress; moved from iOS.js.
(Controller.prototype.handleTimelineInput): Pause if scrubbing; moved from iOS.js.
(Controller.prototype.handleTimelineChange): Update the progress; moved from iOS.js.
(Controller.prototype.showControls): Update the controls width; moved from iOS.js.
(Controller.prototype.hideControls): Removed _potentiallyScrubbing check; not needed due to changes
    to controlsAlwaysVisible().
(Controller.prototype.scheduleUpdateLayoutForDisplayedWidth): Moved from iOS.js.
(Controller.prototype.isControlVisible): Added; checks whether control is parented & not hidden.
(Controller.prototype.updateLayoutForDisplayedWidth): Moved from iOS.js and refactored.
(Controller.prototype.controlsAlwaysVisible): Return true if scrubbing.
(Controller.prototype.updateHasAudio): Check currentPlaybackTargetIsWireless(); moved from iOS.js.
(Controller.prototype.get scrubbing): Simple getter for _scrubbing.
(Controller.prototype.set scrubbing): Check play state if scrubbing; start playback (if necessary)
    if not scrubbing.
(Controller.prototype.get pageScaleFactor): Moved from iOS.js.
(Controller.prototype.set pageScaleFactor): Ditto.
(Controller.prototype.handleRootResize): Schedule an update of the contrtols width.

Remove a bunch of newly unnecessary code from the iOS media controls:

* Modules/mediacontrols/mediaControlsiOS.js:
(ControllerIOS):
(ControllerIOS.prototype.createControls): Remove ivars moved into Apple.js.
(ControllerIOS.prototype.configureInlineControls): Remove spacer; made unnecessary.
(ControllerIOS.prototype.showControls): Deleted.
(ControllerIOS.prototype.updateTime): Deleted.
(ControllerIOS.prototype.handleTimelineTouchStart): Just call "scrubbing = true", handled in Apple.js.
(ControllerIOS.prototype.handleTimelineTouchEnd): Just call "scrubbing = false", handled in Apple.js.
(ControllerIOS.prototype.handleReadyStateChange): Deleted.
(ControllerIOS.prototype.setPlaying): Don't check _timelineIsHidden; not needed.
(ControllerIOS.prototype.get pageScaleFactor): Deleted.
(ControllerIOS.prototype.set pageScaleFactor): Deleted.
(ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Deleted.
(ControllerIOS.prototypeupdateLayoutForDisplayedWidth): Deleted.

Fire a "resize" event at the shadow DOM root when layout results in a size change.

* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::layoutSizeChanged): Fire the "resize" event at the shadow DOM.
* html/HTMLMediaElement.h:
* rendering/RenderMedia.cpp:
(WebCore::RenderMedia::layout): Trigger layoutSizeChanged()
* rendering/RenderMedia.h:

Drive-by fixes:

* Modules/mediacontrols/mediaControlsApple.js:
(Controller.prototype.createControls): aria-label text is totally wrong; removed.
(Controller.prototype.updateWirelessPlaybackStatus): Use class-names to hide controls, not inline styles.

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

Source/WebCore/ChangeLog
Source/WebCore/Modules/mediacontrols/mediaControlsApple.css
Source/WebCore/Modules/mediacontrols/mediaControlsApple.js
Source/WebCore/Modules/mediacontrols/mediaControlsiOS.js
Source/WebCore/html/HTMLMediaElement.cpp
Source/WebCore/html/HTMLMediaElement.h
Source/WebCore/rendering/RenderMedia.cpp
Source/WebCore/rendering/RenderMedia.h

index dc3cc58..8d0e6bd 100644 (file)
@@ -1,3 +1,73 @@
+2015-05-15  Jer Noble  <jer.noble@apple.com>
+
+        [MediaControls] Refactor media controls & bring improvements made to iOS controls to Mac.
+        https://bugs.webkit.org/show_bug.cgi?id=144973
+
+        Reviewed by Dean Jackson.
+
+        Pull improvements made to the iOS media controls back into the Mac controls by moving
+        code from mediaControlsiOS.js into MediaControlsApple.js.
+
+        The largest refactored feature is the ability to drop individual controls from the media
+        controls when the video is too small to contain them. To allow these controls to resize
+        dynamically, a new "resize" event is fired inside the media element's shadow DOM.
+
+        * Modules/mediacontrols/mediaControlsApple.css:
+        (audio::-webkit-media-controls-panel .dropped): Added; sets "display: none".
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller): Set defaults for new variables.
+        (Controller.prototype.updateControls): Update the controls width; moved from iOS.js.
+        (Controller.prototype.handleReadyStateChange): Update the controls; moved from iOS.js.
+        (Controller.prototype.handleTimeUpdate): Update the progress; moved from iOS.js.
+        (Controller.prototype.handleTimelineInput): Pause if scrubbing; moved from iOS.js.
+        (Controller.prototype.handleTimelineChange): Update the progress; moved from iOS.js.
+        (Controller.prototype.showControls): Update the controls width; moved from iOS.js.
+        (Controller.prototype.hideControls): Removed _potentiallyScrubbing check; not needed due to changes
+            to controlsAlwaysVisible().
+        (Controller.prototype.scheduleUpdateLayoutForDisplayedWidth): Moved from iOS.js.
+        (Controller.prototype.isControlVisible): Added; checks whether control is parented & not hidden.
+        (Controller.prototype.updateLayoutForDisplayedWidth): Moved from iOS.js and refactored.
+        (Controller.prototype.controlsAlwaysVisible): Return true if scrubbing.
+        (Controller.prototype.updateHasAudio): Check currentPlaybackTargetIsWireless(); moved from iOS.js.
+        (Controller.prototype.get scrubbing): Simple getter for _scrubbing.
+        (Controller.prototype.set scrubbing): Check play state if scrubbing; start playback (if necessary)
+            if not scrubbing.
+        (Controller.prototype.get pageScaleFactor): Moved from iOS.js.
+        (Controller.prototype.set pageScaleFactor): Ditto.
+        (Controller.prototype.handleRootResize): Schedule an update of the contrtols width.
+
+        Remove a bunch of newly unnecessary code from the iOS media controls:
+
+        * Modules/mediacontrols/mediaControlsiOS.js:
+        (ControllerIOS):
+        (ControllerIOS.prototype.createControls): Remove ivars moved into Apple.js.
+        (ControllerIOS.prototype.configureInlineControls): Remove spacer; made unnecessary.
+        (ControllerIOS.prototype.showControls): Deleted.
+        (ControllerIOS.prototype.updateTime): Deleted.
+        (ControllerIOS.prototype.handleTimelineTouchStart): Just call "scrubbing = true", handled in Apple.js.
+        (ControllerIOS.prototype.handleTimelineTouchEnd): Just call "scrubbing = false", handled in Apple.js.
+        (ControllerIOS.prototype.handleReadyStateChange): Deleted.
+        (ControllerIOS.prototype.setPlaying): Don't check _timelineIsHidden; not needed.
+        (ControllerIOS.prototype.get pageScaleFactor): Deleted.
+        (ControllerIOS.prototype.set pageScaleFactor): Deleted.
+        (ControllerIOS.prototype.scheduleUpdateLayoutForDisplayedWidth): Deleted.
+        (ControllerIOS.prototypeupdateLayoutForDisplayedWidth): Deleted.
+
+        Fire a "resize" event at the shadow DOM root when layout results in a size change.
+
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::layoutSizeChanged): Fire the "resize" event at the shadow DOM.
+        * html/HTMLMediaElement.h:
+        * rendering/RenderMedia.cpp:
+        (WebCore::RenderMedia::layout): Trigger layoutSizeChanged()
+        * rendering/RenderMedia.h:
+
+        Drive-by fixes:
+
+        * Modules/mediacontrols/mediaControlsApple.js:
+        (Controller.prototype.createControls): aria-label text is totally wrong; removed.
+        (Controller.prototype.updateWirelessPlaybackStatus): Use class-names to hide controls, not inline styles.
+
 2015-05-15  Alex Christensen  <achristensen@webkit.org>
 
         [Content Extensions] Fail to load old content extension files
index 1f0828b..23aeff0 100644 (file)
@@ -598,7 +598,9 @@ audio::-webkit-media-controls-panel.hidden {
 }
 
 video::-webkit-media-controls-panel .hidden,
-audio::-webkit-media-controls-panel .hidden {
+audio::-webkit-media-controls-panel .hidden,
+video::-webkit-media-controls-panel .dropped,
+audio::-webkit-media-controls-panel .dropped {
     display: none;
 }
 
index a3d5eaf..2cfa8dc 100644 (file)
@@ -17,6 +17,9 @@ function Controller(root, video, host)
     this.currentTargetIsWireless = false;
     this.wirelessPlaybackDisabled = false;
     this.isVolumeSliderActive = false;
+    this.currentDisplayWidth = 0;
+    this._scrubbing = false;
+    this._pageScaleFactor = 1;
 
     this.addVideoListeners();
     this.createBase();
@@ -37,6 +40,9 @@ function Controller(root, video, host)
     this.updateHasVideo();
     this.updateWirelessTargetAvailable();
     this.updateWirelessPlaybackStatus();
+    this.scheduleUpdateLayoutForDisplayedWidth();
+
+    this.listenFor(this.root, 'resize', this.handleRootResize);
 };
 
 /* Enums */
@@ -81,6 +87,7 @@ Controller.prototype = {
     SeekDelay: 1500,
     ClassNames: {
         active: 'active',
+        dropped: 'dropped',
         exit: 'exit',
         failed: 'failed',
         hidden: 'hidden',
@@ -118,6 +125,8 @@ Controller.prototype = {
         right: 39,
         down: 40
     },
+    MinimumTimelineWidth: 150,
+    ButtonWidth: 32,
 
     extend: function(child)
     {
@@ -457,8 +466,7 @@ Controller.prototype = {
         inlinePlaybackPlaceholder.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-status');
         if (!Controller.gSimulateOptimizedFullscreenAvailable)
             inlinePlaybackPlaceholder.classList.add(this.ClassNames.hidden);
-        inlinePlaybackPlaceholder.setAttribute('aria-label', this.UIString('Display Optimized Full Screen'));
-        
+
         var inlinePlaybackPlaceholderText = this.controls.inlinePlaybackPlaceholderText = document.createElement('div');
         inlinePlaybackPlaceholderText.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-text');
         
@@ -593,6 +601,8 @@ Controller.prototype = {
         else
             this.setControlsType(Controller.InlineControls);
 
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
         this.setNeedsTimelineMetricsUpdate();
     },
 
@@ -657,12 +667,15 @@ Controller.prototype = {
         this.updateFullscreenButtons();
         this.updateWirelessTargetPickerButton();
         this.updateProgress();
+        this.updateControls();
     },
 
     handleTimeUpdate: function(event)
     {
-        if (!this.scrubbing)
+        if (!this.scrubbing) {
             this.updateTime();
+            this.updateProgress();
+        }
         this.drawTimelineBackground();
     },
 
@@ -851,6 +864,9 @@ Controller.prototype = {
 
     handleTimelineInput: function(event)
     {
+        if (this.scrubbing)
+            this.video.pause();
+
         this.video.fastSeek(this.controls.timeline.value);
         this.updateControlsWhileScrubbing();
     },
@@ -858,6 +874,7 @@ Controller.prototype = {
     handleTimelineChange: function(event)
     {
         this.video.currentTime = this.controls.timeline.value;
+        this.updateProgress();
     },
 
     handleTimelineDown: function(event)
@@ -995,6 +1012,8 @@ Controller.prototype = {
         var shouldBeHidden = !this.video.webkitSupportsFullscreen || !this.hasVideo();
         this.controls.fullscreenButton.classList.toggle(this.ClassNames.hidden, shouldBeHidden);
         this.controls.optimizedFullscreenButton.classList.toggle(this.ClassNames.hidden, shouldBeHidden);
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
     },
 
     handleFullscreenButtonClicked: function(event)
@@ -1346,6 +1365,7 @@ Controller.prototype = {
         if (this.showInlinePlaybackPlaceholderOnly())
             return;
 
+        this.updateLayoutForDisplayedWidth();
         this.setNeedsTimelineMetricsUpdate();
         this.updateTime(true);
         this.updateProgress(true);
@@ -1362,7 +1382,7 @@ Controller.prototype = {
 
     hideControls: function()
     {
-        if (this.controlsAlwaysVisible() || this._potentiallyScrubbing)
+        if (this.controlsAlwaysVisible())
             return;
 
         this.updateShouldListenForPlaybackTargetAvailabilityEvent();
@@ -1371,9 +1391,66 @@ Controller.prototype = {
             this.controls.panelBackground.classList.remove(this.ClassNames.show);
     },
 
+    setNeedsUpdateForDisplayedWidth: function()
+    {
+        this.currentDisplayWidth = 0;
+    },
+
+    scheduleUpdateLayoutForDisplayedWidth: function()
+    {
+        setTimeout(this.updateLayoutForDisplayedWidth.bind(this), 0);
+    },
+
+    isControlVisible: function(control)
+    {
+        if (!control)
+            return false;
+        if (!this.root.contains(control))
+            return false;
+        return !control.classList.contains(this.ClassNames.hidden)
+    },
+
+    updateLayoutForDisplayedWidth: function()
+    {
+        if (!this.controls || !this.controls.panel)
+            return;
+
+        var visibleWidth = this.controls.panel.getBoundingClientRect().width * this._pageScaleFactor;
+        if (visibleWidth <= 0 || visibleWidth == this.currentDisplayWidth)
+            return;
+
+        this.currentDisplayWidth = visibleWidth;
+
+        // Filter all the buttons which are not explicitly hidden.
+        var buttons = [this.controls.playButton, this.controls.rewindButton, this.controls.captionButton,
+                       this.controls.fullscreenButton, this.controls.optimizedFullscreenButton,
+                       this.controls.wirelessTargetPicker, this.controls.muteBox];
+        var visibleButtons = buttons.filter(this.isControlVisible, this);
+
+        // This tells us how much room we need in order to display every visible button.
+        var visibleButtonWidth = this.ButtonWidth * visibleButtons.length;
+
+        // Check if there is enough room for the scrubber.
+        var shouldDropTimeline = (visibleWidth - visibleButtonWidth) < this.MinimumTimelineWidth;
+        this.controls.currentTime.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+        this.controls.thumbnailTrack.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+        this.controls.remainingTime.classList.toggle(this.ClassNames.dropped, shouldDropTimeline);
+
+        // Then controls in the following order:
+        var removeOrder = [this.controls.wirelessTargetPicker, this.controls.optimizedFullscreenButton,
+                           this.controls.captionButton, this.controls.muteBox, this.controls.rewindButton,
+                           this.controls.fullscreenButton];
+        removeOrder.forEach(function(control) {
+            var shouldDropControl = visibleWidth < visibleButtonWidth && this.isControlVisible(control);
+            control.classList.toggle(this.ClassNames.dropped, shouldDropControl);
+            if (shouldDropControl)
+                visibleButtonWidth -= this.ButtonWidth;
+        }, this);
+    },
+
     controlsAlwaysVisible: function()
     {
-        return this.isAudio() || this.currentPlaybackTargetIsWireless();
+        return this.isAudio() || this.currentPlaybackTargetIsWireless() || this.scrubbing;
     },
 
     controlsAreHidden: function()
@@ -1472,6 +1549,8 @@ Controller.prototype = {
             this.controls.captionButton.classList.remove(this.ClassNames.hidden);
         else
             this.controls.captionButton.classList.add(this.ClassNames.hidden);
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
     },
 
     updateCaptionContainer: function()
@@ -1737,10 +1816,13 @@ Controller.prototype = {
 
     updateHasAudio: function()
     {
-        if (this.video.audioTracks.length)
+        if (this.video.audioTracks.length && !this.currentPlaybackTargetIsWireless())
             this.controls.muteBox.classList.remove(this.ClassNames.hidden);
         else
             this.controls.muteBox.classList.add(this.ClassNames.hidden);
+
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
     },
 
     updateHasVideo: function()
@@ -1837,20 +1919,18 @@ Controller.prototype = {
                 this.controls.inlinePlaybackPlaceholderTextTop.classList.remove(this.ClassNames.small);
                 this.controls.inlinePlaybackPlaceholderTextBottom.classList.remove(this.ClassNames.small);
             }
-            if (this.isFullScreen())
-                this.controls.volumeBox.style.display = "none";
-            else
-                this.controls.muteBox.style.display = "none";
+            this.controls.volumeBox.classList.add(this.ClassNames.hidden);
+            this.controls.muteBox.classList.add(this.ClassNames.hidden);
             this.updateBase();
             this.showControls();
         } else {
             this.controls.inlinePlaybackPlaceholder.classList.add(this.ClassNames.hidden);
             this.controls.wirelessTargetPicker.classList.remove(this.ClassNames.playing);
-            if (this.isFullScreen())
-                this.controls.volumeBox.style.display = "-webkit-flex";
-            else
-                this.controls.muteBox.style.display = "-webkit-flex";
+            this.controls.volumeBox.classList.remove(this.ClassNames.hidden);
+            this.controls.muteBox.classList.remove(this.ClassNames.hidden);
         }
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
         this.updateWirelessTargetPickerButton();
     },
 
@@ -1866,6 +1946,8 @@ Controller.prototype = {
             this.controls.wirelessTargetPicker.classList.remove(this.ClassNames.hidden);
         else
             this.controls.wirelessTargetPicker.classList.add(this.ClassNames.hidden);
+        this.setNeedsUpdateForDisplayedWidth();
+        this.updateLayoutForDisplayedWidth();
     },
 
     handleWirelessPickerButtonClicked: function(event)
@@ -1911,4 +1993,50 @@ Controller.prototype = {
         return this.currentPlaybackTargetIsWireless() && !this.video.controls;
     },
 
+    get scrubbing()
+    {
+        return this._scrubbing;
+    },
+
+    set scrubbing(flag)
+    {
+        if (this._scrubbing == flag)
+            return;
+        this._scrubbing = flag;
+
+        if (this._scrubbing)
+            this.wasPlayingWhenScrubbingStarted = !this.video.paused;
+        else if (this.wasPlayingWhenScrubbingStarted && this.video.paused) {
+            this.video.play();
+            this.resetHideControlsTimer();
+        }
+    },
+
+    get pageScaleFactor()
+    {
+        return this._pageScaleFactor;
+    },
+
+    set pageScaleFactor(newScaleFactor)
+    {
+        if (this._pageScaleFactor === newScaleFactor)
+            return;
+
+        this._pageScaleFactor = newScaleFactor;
+
+        // FIXME: this should react to the scale change by
+        // unscaling the controls panel. However, this
+        // hits a bug with the backdrop blur layer getting
+        // too big and moving to a tiled layer.
+        // https://bugs.webkit.org/show_bug.cgi?id=142317
+    },
+
+    handleRootResize: function(event)
+    {
+        this.updateLayoutForDisplayedWidth();
+        this.setNeedsTimelineMetricsUpdate();
+        this.updateTimelineMetricsIfNeeded();
+        this.drawTimelineBackground();
+    }
+
 };
index 96c77d2..7ea4812 100644 (file)
@@ -16,22 +16,21 @@ function ControllerIOS(root, video, host)
 
     this._timelineIsHidden = false;
     this._currentDisplayWidth = 0;
-    this._potentiallyScrubbing = false;
     this.scheduleUpdateLayoutForDisplayedWidth();
 
     host.controlsDependOnPageScaleFactor = true;
     this.doingSetup = false;
 };
 
-/* Constants */
-ControllerIOS.MinimumTimelineWidth = 200;
-ControllerIOS.ButtonWidth = 42;
-
 /* Enums */
 ControllerIOS.StartPlaybackControls = 2;
 
 
 ControllerIOS.prototype = {
+    /* Constants */
+    MinimumTimelineWidth: 200,
+    ButtonWidth: 42,
+
     addVideoListeners: function() {
         Controller.prototype.addVideoListeners.call(this);
 
@@ -112,10 +111,6 @@ ControllerIOS.prototype = {
         var panelBackground = this.controls.panelBackground = document.createElement('div');
         panelBackground.setAttribute('pseudo', '-webkit-media-controls-panel-background');
 
-        var spacer = this.controls.spacer = document.createElement('div');
-        spacer.setAttribute('pseudo', '-webkit-media-controls-spacer');
-        spacer.classList.add(this.ClassNames.hidden);
-
         var inlinePlaybackPlaceholderText = this.controls.inlinePlaybackPlaceholderText = document.createElement('div');
         inlinePlaybackPlaceholderText.setAttribute('pseudo', '-webkit-media-controls-wireless-playback-text');
 
@@ -186,7 +181,6 @@ ControllerIOS.prototype = {
         this.controls.inlinePlaybackPlaceholderText.appendChild(this.controls.inlinePlaybackPlaceholderTextBottom);
         this.controls.panel.appendChild(this.controls.playButton);
         this.controls.panel.appendChild(this.controls.statusDisplay);
-        this.controls.panel.appendChild(this.controls.spacer);
         this.controls.panel.appendChild(this.controls.timelineBox);
         this.controls.panel.appendChild(this.controls.wirelessTargetPicker);
         if (!this.isLive) {
@@ -208,13 +202,6 @@ ControllerIOS.prototype = {
         // Explicitly do nothing to override base-class behavior.
     },
 
-    showControls: function() {
-        this.updateLayoutForDisplayedWidth();
-        this.updateTime(true);
-        this.updateProgress(true);
-        Controller.prototype.showControls.call(this);
-    },
-
     addControls: function() {
         this.base.appendChild(this.controls.inlinePlaybackPlaceholder);
         this.base.appendChild(this.controls.panelContainer);
@@ -235,11 +222,6 @@ ControllerIOS.prototype = {
         this.setNeedsTimelineMetricsUpdate();
     },
 
-    updateTime: function(forceUpdate) {
-        Controller.prototype.updateTime.call(this, forceUpdate);
-        this.updateProgress();
-    },
-
     drawTimelineBackground: function() {
         var width = this.timelineWidth * window.devicePixelRatio;
         var height = this.timelineHeight * window.devicePixelRatio;
@@ -493,20 +475,8 @@ ControllerIOS.prototype = {
         return true;
     },
 
-    handleTimelineInput: function(event) {
-        if (this._potentiallyScrubbing)
-            this.video.pause();
-        Controller.prototype.handleTimelineInput.call(this, event);
-    },
-
-    handleTimelineChange: function(event) {
-        Controller.prototype.handleTimelineChange.call(this, event);
-        this.updateProgress();
-    },
-
     handleTimelineTouchStart: function(event) {
-        this._potentiallyScrubbing = true;
-        this.wasPlayingWhenScrubbingStarted = !this.video.paused;
+        this.scrubbing = true;
         this.listenFor(this.controls.timeline, 'touchend', this.handleTimelineTouchEnd);
         this.listenFor(this.controls.timeline, 'touchcancel', this.handleTimelineTouchEnd);
     },
@@ -514,16 +484,7 @@ ControllerIOS.prototype = {
     handleTimelineTouchEnd: function(event) {
         this.stopListeningFor(this.controls.timeline, 'touchend', this.handleTimelineTouchEnd);
         this.stopListeningFor(this.controls.timeline, 'touchcancel', this.handleTimelineTouchEnd);
-        this._potentiallyScrubbing = false;
-        if (this.wasPlayingWhenScrubbingStarted && this.video.paused) {
-            this.video.play();
-            this.resetHideControlsTimer();
-        }
-    },
-
-    handleReadyStateChange: function(event) {
-        Controller.prototype.handleReadyStateChange.call(this, event);
-        this.updateControls();
+        this.scrubbing = false;
     },
 
     handleWirelessPickerButtonTouchStart: function() {
@@ -562,10 +523,8 @@ ControllerIOS.prototype = {
 
         this.updateControls();
 
-        if (isPlaying && this.isAudio() && !this._timelineIsHidden) {
+        if (isPlaying && this.isAudio())
             this.controls.timelineBox.classList.remove(this.ClassNames.hidden);
-            this.controls.spacer.classList.add(this.ClassNames.hidden);
-        }
 
         if (isPlaying)
             this.hasPlayed = true;
@@ -581,25 +540,6 @@ ControllerIOS.prototype = {
         Controller.prototype.setShouldListenForPlaybackTargetAvailabilityEvent.call(this, shouldListen);
     },
 
-    get pageScaleFactor()
-    {
-        return this._pageScaleFactor;
-    },
-
-    set pageScaleFactor(newScaleFactor)
-    {
-        if (this._pageScaleFactor === newScaleFactor)
-            return;
-
-        this._pageScaleFactor = newScaleFactor;
-
-        // FIXME: this should react to the scale change by
-        // unscaling the controls panel. However, this
-        // hits a bug with the backdrop blur layer getting
-        // too big and moving to a tiled layer.
-        // https://bugs.webkit.org/show_bug.cgi?id=142317
-    },
-
     handlePresentationModeChange: function(event)
     {
         var presentationMode = this.presentationMode();
@@ -628,69 +568,6 @@ ControllerIOS.prototype = {
         this.handlePresentationModeChange(event);
     },
 
-    scheduleUpdateLayoutForDisplayedWidth: function ()
-    {
-        setTimeout(function () {
-            this.updateLayoutForDisplayedWidth();
-        }.bind(this), 0);
-    },
-
-    updateLayoutForDisplayedWidth: function()
-    {
-        if (!this.controls || !this.controls.panel)
-            return;
-
-        var visibleWidth = this.controls.panel.getBoundingClientRect().width * this._pageScaleFactor;
-        if (visibleWidth <= 0 || visibleWidth == this._currentDisplayWidth)
-            return;
-
-        this._currentDisplayWidth = visibleWidth;
-
-        // We need to work out how many right-hand side buttons are available.
-        this.updateWirelessTargetAvailable();
-        this.updateFullscreenButtons();
-
-        var visibleButtonWidth = ControllerIOS.ButtonWidth; // We always try to show the fullscreen button.
-
-        if (!this.controls.wirelessTargetPicker.classList.contains(this.ClassNames.hidden))
-            visibleButtonWidth += ControllerIOS.ButtonWidth;
-        if (!this.controls.optimizedFullscreenButton.classList.contains(this.ClassNames.hidden))
-            visibleButtonWidth += ControllerIOS.ButtonWidth;
-
-        // Check if there is enough room for the scrubber.
-        if ((visibleWidth - visibleButtonWidth) < ControllerIOS.MinimumTimelineWidth) {
-            this.controls.timelineBox.classList.add(this.ClassNames.hidden);
-            this.controls.spacer.classList.remove(this.ClassNames.hidden);
-            this._timelineIsHidden = true;
-        } else {
-            if (!this.isAudio() || this.hasPlayed) {
-                this.controls.timelineBox.classList.remove(this.ClassNames.hidden);
-                this.controls.spacer.classList.add(this.ClassNames.hidden);
-                this._timelineIsHidden = false;
-            } else
-                this.controls.spacer.classList.remove(this.ClassNames.hidden);
-        }
-
-        // Drop the airplay button if there isn't enough space.
-        if (visibleWidth < visibleButtonWidth) {
-            this.controls.wirelessTargetPicker.classList.add(this.ClassNames.hidden);
-            visibleButtonWidth -= ControllerIOS.ButtonWidth;
-        }
-
-        // Drop the optimized fullscreen button if there still isn't enough space.
-        if (visibleWidth < visibleButtonWidth) {
-            this.controls.optimizedFullscreenButton.classList.add(this.ClassNames.hidden);
-            visibleButtonWidth -= ControllerIOS.ButtonWidth;
-        }
-
-        // And finally, drop the fullscreen button as a last resort.
-        if (visibleWidth < visibleButtonWidth) {
-            this.controls.fullscreenButton.classList.add(this.ClassNames.hidden);
-            visibleButtonWidth -= ControllerIOS.ButtonWidth;
-        } else
-            this.controls.fullscreenButton.classList.remove(this.ClassNames.hidden);
-    },
-
     controlsAlwaysVisible: function()
     {
         if (this.presentationMode() === 'optimized')
index a4f21c1..0ff86aa 100644 (file)
@@ -261,6 +261,8 @@ HTMLMediaElement::HTMLMediaElement(const QualifiedName& tagName, Document& docum
     , m_playbackProgressTimer(*this, &HTMLMediaElement::playbackProgressTimerFired)
     , m_scanTimer(*this, &HTMLMediaElement::scanTimerFired)
     , m_seekTaskQueue(document)
+    , m_resizeTaskQueue(document)
+    , m_shadowDOMTaskQueue(document)
     , m_playedTimeRanges()
     , m_asyncEventQueue(*this)
     , m_requestedPlaybackRate(1)
@@ -3776,6 +3778,18 @@ void HTMLMediaElement::updateCaptionContainer()
     exec->clearException();
 #endif
 }
+
+void HTMLMediaElement::layoutSizeChanged()
+{
+#if ENABLE(MEDIA_CONTROLS_SCRIPT)
+    RefPtr<HTMLMediaElement> strongThis = this;
+    std::function<void()> task = [strongThis] {
+        if (ShadowRoot* root = strongThis->userAgentShadowRoot())
+            root->dispatchEvent(Event::create("resize", false, false));
+    };
+    m_resizeTaskQueue.enqueueTask(task);
+#endif
+}
     
 void HTMLMediaElement::setSelectedTextTrack(TextTrack* trackToSelect)
 {
@@ -5707,7 +5721,6 @@ String HTMLMediaElement::mediaPlayerUserAgent() const
         return String();
 
     return frame->loader().userAgent(m_currentSrc);
-
 }
 
 #if ENABLE(AVF_CAPTIONS)
@@ -6002,6 +6015,7 @@ static void setPageScaleFactorProperty(JSC::ExecState* exec, JSC::JSValue contro
 void HTMLMediaElement::didAddUserAgentShadowRoot(ShadowRoot* root)
 {
     LOG(Media, "HTMLMediaElement::didAddUserAgentShadowRoot(%p)", this);
+
     Page* page = document().page();
     if (!page)
         return;
index 3b661ab..92cce86 100644 (file)
@@ -459,6 +459,8 @@ public:
 
     virtual MediaProducer::MediaStateFlags mediaState() const override;
 
+    void layoutSizeChanged();
+
 protected:
     HTMLMediaElement(const QualifiedName&, Document&, bool);
     virtual ~HTMLMediaElement();
@@ -748,6 +750,8 @@ private:
     Timer m_playbackProgressTimer;
     Timer m_scanTimer;
     GenericTaskQueue<ScriptExecutionContext> m_seekTaskQueue;
+    GenericTaskQueue<ScriptExecutionContext> m_resizeTaskQueue;
+    GenericTaskQueue<ScriptExecutionContext> m_shadowDOMTaskQueue;
     RefPtr<TimeRanges> m_playedTimeRanges;
     GenericEventQueue m_asyncEventQueue;
 
index afebc9d..d645fe8 100644 (file)
@@ -55,6 +55,15 @@ void RenderMedia::paintReplaced(PaintInfo&, const LayoutPoint&)
 {
 }
 
+void RenderMedia::layout()
+{
+    LayoutSize oldSize = size();
+    RenderImage::layout();
+    if (oldSize != size())
+        mediaElement().layoutSizeChanged();
+}
+
+
 } // namespace WebCore
 
 #endif
index d640472..b64e325 100644 (file)
@@ -41,6 +41,9 @@ public:
 
     HTMLMediaElement& mediaElement() const { return downcast<HTMLMediaElement>(nodeForNonAnonymous()); }
 
+protected:
+    virtual void layout() override;
+
 private:
     void element() const = delete;