Index: Source/core/html/shadow/MediaControls.cpp |
diff --git a/Source/core/html/shadow/MediaControls.cpp b/Source/core/html/shadow/MediaControls.cpp |
index 17d1096113fffeb9acbde1c6aaa10e83a405b48e..1325e20a7756d0398be662acb070f08f1a182a9a 100644 |
--- a/Source/core/html/shadow/MediaControls.cpp |
+++ b/Source/core/html/shadow/MediaControls.cpp |
@@ -35,6 +35,7 @@ |
#include "core/html/MediaController.h" |
#include "core/html/track/TextTrackContainer.h" |
#include "core/layout/LayoutTheme.h" |
+#include "public/platform/Platform.h" |
philipj_slow
2015/07/08 15:06:38
It doesn't look like this include is needed.
liberato (no reviews please)
2015/07/09 12:10:56
Done.
|
namespace blink { |
@@ -89,9 +90,9 @@ PassRefPtrWillBeRawPtr<MediaControls> MediaControls::create(HTMLMediaElement& me |
// \-MediaControlPanelEnclosureElement (-webkit-media-controls-enclosure) |
// \-MediaControlPanelElement (-webkit-media-controls-panel) |
// +-MediaControlPlayButtonElement (-webkit-media-controls-play-button) |
-// +-MediaControlTimelineElement (-webkit-media-controls-timeline) |
// +-MediaControlCurrentTimeDisplayElement (-webkit-media-controls-current-time-display) |
// +-MediaControlTimeRemainingDisplayElement (-webkit-media-controls-time-remaining-display) |
+// +-MediaControlTimelineElement (-webkit-media-controls-timeline) |
philipj_slow
2015/07/08 15:06:38
Can you keep it in both places and annotated with
liberato (no reviews please)
2015/07/09 12:10:56
Done.
|
// +-MediaControlMuteButtonElement (-webkit-media-controls-mute-button) |
// +-MediaControlVolumeSliderElement (-webkit-media-controls-volume-slider) |
// +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-toggle-closed-captions-button) |
@@ -125,24 +126,43 @@ void MediaControls::initializeControls() |
RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(*this); |
m_timeline = timeline.get(); |
- panel->appendChild(timeline.release()); |
+ // In old UX, timeline is before the time / duration text. |
+ if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
+ panel->appendChild(timeline.release()); |
+ // else we will attach it later. |
RefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(*this); |
m_currentTimeDisplay = currentTimeDisplay.get(); |
- m_currentTimeDisplay->hide(); |
+ if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
+ m_currentTimeDisplay->dontWant(); |
+ else |
+ m_currentTimeDisplay->want(); |
+ |
panel->appendChild(currentTimeDisplay.release()); |
RefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> durationDisplay = MediaControlTimeRemainingDisplayElement::create(*this); |
m_durationDisplay = durationDisplay.get(); |
panel->appendChild(durationDisplay.release()); |
+ // In new UX, timeline is after the time / duration text. |
+ if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
+ panel->appendChild(timeline.release()); |
+ |
RefPtrWillBeRawPtr<MediaControlMuteButtonElement> muteButton = MediaControlMuteButtonElement::create(*this); |
m_muteButton = muteButton.get(); |
panel->appendChild(muteButton.release()); |
+#if OS(ANDROID) |
+ if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
+ m_muteButton->dontWant(); |
+#endif |
RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = MediaControlVolumeSliderElement::create(*this); |
m_volumeSlider = slider.get(); |
panel->appendChild(slider.release()); |
+#if OS(ANDROID) |
+ if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
+ m_volumeSlider->dontWant(); |
+#endif |
RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(*this); |
m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); |
@@ -165,10 +185,24 @@ void MediaControls::initializeControls() |
void MediaControls::reset() |
{ |
+ const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled(); |
double duration = mediaElement().duration(); |
m_durationDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsTime(duration), ASSERT_NO_EXCEPTION); |
m_durationDisplay->setCurrentValue(duration); |
+ if (useNewUi) { |
+ // Show everything that we might hide. |
+ // If we don't have a duration, then mark it to be hidden by |
+ // scheduleUpdateControlsVisibilityForSpace(). For the old UI case, we still |
+ // hide / show it here, too, since update*() won't. |
+ if (std::isfinite(duration)) |
+ m_durationDisplay->want(); |
+ else |
+ m_durationDisplay->dontWant(); |
+ m_currentTimeDisplay->want(); |
+ m_timeline->want(); |
+ } |
+ |
updatePlayState(); |
updateCurrentTimeDisplay(); |
@@ -176,10 +210,20 @@ void MediaControls::reset() |
m_timeline->setDuration(duration); |
m_timeline->setPosition(mediaElement().currentTime()); |
- if (!mediaElement().hasAudio()) |
- m_volumeSlider->hide(); |
- else |
- m_volumeSlider->show(); |
+ if (!mediaElement().hasAudio()) { |
+ m_volumeSlider->dontWant(); |
+ } else { |
+#if OS(ANDROID) |
+ // New UI always hides the volume slider on Android. |
+ if (useNewUi) |
+ m_volumeSlider->dontWant(); |
+ else |
+ m_volumeSlider->want(); |
+#else |
+ m_volumeSlider->want(); |
+#endif |
+ } |
+ |
updateVolume(); |
refreshClosedCaptionsButtonVisibility(); |
@@ -190,13 +234,22 @@ void MediaControls::reset() |
// the button earlier, and we don't want to remove it here if the |
// user chose to enter fullscreen. crbug.com/500732 . |
if ((mediaElement().hasVideo() && fullscreenIsSupported(document())) |
- || mediaElement().isFullscreen()) |
- m_fullScreenButton->show(); |
- else |
- m_fullScreenButton->hide(); |
+ || mediaElement().isFullscreen()) { |
+ m_fullScreenButton->want(); |
+ } else { |
+ m_fullScreenButton->dontWant(); |
+ } |
refreshCastButtonVisibility(); |
+ scheduleUpdateControlsVisibilityForSpace(); |
fs
2015/07/08 09:31:00
First refreshCastButtonVisibility will call update
liberato (no reviews please)
2015/07/09 12:10:56
updated to ...WithoutLayout(), which is now called
|
makeOpaque(); |
+ |
+ // Request resize events from our layout object. Our show / hide logic |
+ // would be better suited to a layout, but JS doesn't have that option. |
+ // So, we opt for an event-based solution to keep the logic JS-friendly, |
+ // though the particular event may change. |
+ if (layoutObject() && useNewUi) |
+ layoutObject()->setSendResizeEvent(true); |
} |
LayoutObject* MediaControls::layoutObjectForTextTrackLayout() |
@@ -263,8 +316,10 @@ bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const |
void MediaControls::playbackStarted() |
{ |
- m_currentTimeDisplay->show(); |
- m_durationDisplay->hide(); |
+ if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) { |
+ m_currentTimeDisplay->want(); |
+ m_durationDisplay->dontWant(); |
+ } |
updatePlayState(); |
m_timeline->setPosition(mediaElement().currentTime()); |
@@ -325,9 +380,9 @@ void MediaControls::updateCurrentTimeDisplay() |
double duration = mediaElement().duration(); |
// After seek, hide duration display and show current time. |
- if (now > 0) { |
- m_currentTimeDisplay->show(); |
- m_durationDisplay->hide(); |
+ if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() && now > 0) { |
+ m_currentTimeDisplay->want(); |
+ m_durationDisplay->dontWant(); |
} |
// Allow the theme to format the time. |
@@ -359,9 +414,9 @@ void MediaControls::changedClosedCaptionsVisibility() |
void MediaControls::refreshClosedCaptionsButtonVisibility() |
{ |
if (mediaElement().hasClosedCaptions()) |
- m_toggleClosedCaptionsButton->show(); |
+ m_toggleClosedCaptionsButton->want(); |
else |
- m_toggleClosedCaptionsButton->hide(); |
+ m_toggleClosedCaptionsButton->dontWant(); |
} |
static Element* elementFromCenter(Element& element) |
@@ -384,6 +439,12 @@ void MediaControls::tryShowOverlayCastButton() |
void MediaControls::refreshCastButtonVisibility() |
{ |
+ refreshCastButtonVisibilityWithoutLayout(); |
+ updateControlsVisibilityForSpace(); |
+} |
+ |
+void MediaControls::refreshCastButtonVisibilityWithoutLayout() |
philipj_slow
2015/07/08 15:06:38
This name doesn't seem right, getBoundingClientRec
liberato (no reviews please)
2015/07/09 12:10:56
"causes no more layouts than before".
i've rename
|
+{ |
if (mediaElement().hasRemoteRoutes()) { |
// The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which |
// doesn't autoplay on Chrome for Android (we prevent it) so starts paused. In such cases we don't want to automatically |
@@ -391,20 +452,31 @@ void MediaControls::refreshCastButtonVisibility() |
// If a user does want to cast a paused autoplay video then they can still do so by touching or clicking on the |
// video, which will cause the cast button to appear. |
if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() && mediaElement().paused()) { |
+ // Note that this is a case where we add the overlay cast button |
+ // without wanting the bar cast button. We depend on the fact |
+ // that scheduleUpdate...() won't change overlay cast button |
+ // visibility in this case. |
showOverlayCastButton(); |
+ m_castButton->dontWant(); |
} else if (mediaElement().shouldShowControls()) { |
m_overlayCastButton->hide(); |
- m_castButton->show(); |
- // Check that the cast button actually fits on the bar. |
- if (m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) { |
- m_castButton->hide(); |
+ m_castButton->want(); |
+ // Check that the cast button actually fits on the bar. For the |
+ // new ui, we let updateControlsVisibilityForSpace() handle this. |
+ if ( !RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() |
+ && m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) { |
+ m_castButton->dontWant(); |
tryShowOverlayCastButton(); |
} |
} |
} else { |
- m_castButton->hide(); |
+ m_castButton->dontWant(); |
m_overlayCastButton->hide(); |
} |
+ |
+ // do NOT updateControls...() here - that triggers a layout. |
+ // we could schedule, I suppose, though be careful that it |
+ // doesn't also trigger one immediately. |
} |
void MediaControls::showOverlayCastButton() |
@@ -451,6 +523,13 @@ void MediaControls::defaultEventHandler(Event* event) |
|| (event->isMouseEvent() && toMouseEvent(event)->fromTouch()); |
m_hideTimerBehaviorFlags |= wasLastEventTouch ? IgnoreControlsHover : IgnoreNone; |
+ // If we get a resize event, then update our controls. Note that if |
+ // we get a resize in the old UI case, update*() will do nothing anyway. |
+ if (event->type() == EventTypeNames::resize) { |
+ updateControlsVisibilityForSpace(); |
+ return; |
+ } |
+ |
if (event->type() == EventTypeNames::mouseover) { |
if (!containsRelatedTarget(event)) { |
m_isMouseOverControls = true; |
@@ -525,6 +604,72 @@ bool MediaControls::containsRelatedTarget(Event* event) |
return contains(relatedTarget->toNode()); |
} |
+void MediaControls::scheduleUpdateControlsVisibilityForSpace() |
+{ |
+ // Schedule an update event for us, of the same type that our LayoutObject |
+ // will send on resize. We post these rather than directly modify |
+ // controls visibility because repaints are missed otherwise. |
+ RefPtrWillBeRawPtr<Event> event = Event::create(EventTypeNames::resize); |
+ event->setTarget(this); |
+ LocalDOMWindow* win = document().executingWindow(); |
+ if (win) |
+ win->eventQueue()->enqueueEvent(event); |
+ |
+ // This causes a relayout when controls are queried, but it also sometimes |
+ // misses paints. As in, mouse over will cause a control to show / hide. |
+ updateControlsVisibilityForSpace(); // So that queries work |
fs
2015/07/08 09:31:00
Having a schedule<operation> that also performs <o
liberato (no reviews please)
2015/07/09 12:10:56
true. it no longer does this.
|
+} |
+ |
+void MediaControls::updateControlsVisibilityForSpace() |
+{ |
+ // Hide all controls that don't fit, and show the ones that do. |
+ // This might be better suited for a layout, but since JS media controls |
+ // won't benefit from that anwyay, we just do it here like JS will. |
+ // The order, in order of decreasing droppiness: |
+ // Volume, time, seek bar, cast. |
+ |
+ int panelWidth = m_panel->clientWidth(); |
+ if (panelWidth == 0) |
+ return; |
+ |
+ // Controls that we'll hide / show, in order of decreasing priority. |
+ MediaControlElement* elements[] = { |
+ m_playButton.get(), |
+ m_toggleClosedCaptionsButton.get(), |
+ m_fullScreenButton.get(), |
+ m_timeline.get(), |
+ m_currentTimeDisplay.get(), |
+ m_volumeSlider.get(), |
+ m_castButton.get(), |
+ m_muteButton.get(), |
+ m_durationDisplay.get(), |
+ 0 |
+ }; |
+ |
+ int usedWidth = 0; |
+ for (int i = 0; elements[i]; i++) { |
+ if (elements[i]->isWanted()) { |
+ if (usedWidth + elements[i]->minimumWidth() <= panelWidth) { |
+ elements[i]->show(); |
+ usedWidth += elements[i]->minimumWidth(); |
+ } else { |
+ elements[i]->hide(); |
+ } |
+ } else { |
+ elements[i]->hide(); // paranoia. |
+ } |
+ } |
+ |
+ // Special case for cast: if we want a cast button but dropped it, then |
+ // show the overlay cast button instead. |
+ if (m_castButton->isWanted()) { |
+ if (!m_castButton->isShown()) |
+ m_overlayCastButton->show(); |
+ else |
+ m_overlayCastButton->hide(); |
+ } // else do not change overlay cast button state. |
+} |
+ |
DEFINE_TRACE(MediaControls) |
{ |
visitor->trace(m_mediaElement); |