Chromium Code Reviews| 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..cf1fc014267bd482ac9c0862a5be39944a102161 100644 |
| --- a/Source/core/html/shadow/MediaControls.cpp |
| +++ b/Source/core/html/shadow/MediaControls.cpp |
| @@ -68,6 +68,8 @@ MediaControls::MediaControls(HTMLMediaElement& mediaElement) |
| , m_hideTimerBehaviorFlags(IgnoreNone) |
| , m_isMouseOverControls(false) |
| , m_isPausedForScrubbing(false) |
| + , m_panelWidthChangedTimer(this, &MediaControls::panelWidthChangedTimerFired) |
| + , m_panelWidth(0) |
| { |
| } |
| @@ -89,9 +91,10 @@ 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) |
| +// +-MediaControlTimelineElement (-webkit-media-controls-timeline) (if !RTE::newMediaPlaybackUi()) |
|
philipj_slow
2015/07/09 08:56:10
Can you use the same style as the above {if mediaC
liberato (no reviews please)
2015/07/09 22:35:34
done. didn't realize that's what it meant.
philipj_slow
2015/07/09 23:18:37
fs pulled the syntax out of a hat, and I just like
|
| // +-MediaControlCurrentTimeDisplayElement (-webkit-media-controls-current-time-display) |
| // +-MediaControlTimeRemainingDisplayElement (-webkit-media-controls-time-remaining-display) |
| +// +-MediaControlTimelineElement (-webkit-media-controls-timeline) (if RTE::newMediaPlaybackUi()) |
| // +-MediaControlMuteButtonElement (-webkit-media-controls-mute-button) |
| // +-MediaControlVolumeSliderElement (-webkit-media-controls-volume-slider) |
| // +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-toggle-closed-captions-button) |
| @@ -125,24 +128,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()) |
|
philipj_slow
2015/07/09 08:56:10
Break out this into a local variable like in ::res
liberato (no reviews please)
2015/07/09 22:35:34
Done.
|
| + 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()) |
|
philipj_slow
2015/07/09 08:56:10
Transform this into a single setIsWanted() call.
liberato (no reviews please)
2015/07/09 22:35:34
Done.
|
| + m_currentTimeDisplay->setIsWanted(false); |
| + else |
| + m_currentTimeDisplay->setIsWanted(true); |
| + |
| 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) |
|
philipj_slow
2015/07/09 08:56:10
Is this actually needed? Should work the same if d
liberato (no reviews please)
2015/07/09 12:10:57
since we unhide mute to handle the 'media starts m
|
| + if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
| + m_muteButton->setIsWanted(false); |
| +#endif |
| RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = MediaControlVolumeSliderElement::create(*this); |
| m_volumeSlider = slider.get(); |
| panel->appendChild(slider.release()); |
| +#if OS(ANDROID) |
| + if (RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) |
| + m_volumeSlider->setIsWanted(false); |
| +#endif |
| RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(*this); |
| m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); |
| @@ -165,10 +187,24 @@ void MediaControls::initializeControls() |
| void MediaControls::reset() |
| { |
| + const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled(); |
|
philipj_slow
2015/07/09 08:56:10
Also make duration const if you prefer that. (If y
liberato (no reviews please)
2015/07/09 12:10:57
i've always assumed that it's a note to myself mor
|
| 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. For the |
| + // old UI case, want / don't want is the same as show / hide since |
| + // it is never marked as not fitting. |
| + if (std::isfinite(duration)) |
| + m_durationDisplay->setIsWanted(true); |
| + else |
| + m_durationDisplay->setIsWanted(false); |
| + m_currentTimeDisplay->setIsWanted(true); |
| + m_timeline->setIsWanted(true); |
| + } |
| + |
| updatePlayState(); |
| updateCurrentTimeDisplay(); |
| @@ -176,10 +212,23 @@ 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->setIsWanted(false); |
|
philipj_slow
2015/07/09 08:56:10
Ditto.
liberato (no reviews please)
2015/07/09 22:35:34
this one always ends up worse with the #ifdef.
philipj_slow
2015/07/09 23:18:37
Oh, here it wasn't actually m_volumeSlider and m_m
|
| + if (useNewUi) |
| + m_muteButton->setIsWanted(false); |
| + } else { |
| +#if OS(ANDROID) |
|
philipj_slow
2015/07/09 08:56:10
Should also be possible to do with just CSS.
liberato (no reviews please)
2015/07/09 22:35:34
true, but this way it's all in one spot. otherwis
philipj_slow
2015/07/09 23:18:37
Oh, so before it was always an option to hide usin
liberato (no reviews please)
2015/07/10 07:20:30
i've added settings()->preferHidden{VolumeSlider,
|
| + // New UI always hides the volume slider on Android. |
| + if (useNewUi) |
| + m_volumeSlider->setIsWanted(false); |
|
philipj_slow
2015/07/09 08:56:10
Ditto.
liberato (no reviews please)
2015/07/09 22:35:33
Done.
|
| + else |
| + m_volumeSlider->setIsWanted(true); |
| +#else |
| + m_volumeSlider->setIsWanted(true); |
| + m_muteButton->setIsWanted(true); |
| +#endif |
| + } |
| + |
| updateVolume(); |
| refreshClosedCaptionsButtonVisibility(); |
| @@ -190,13 +239,15 @@ 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->setIsWanted(true); |
|
philipj_slow
2015/07/09 08:56:10
Ditto.
liberato (no reviews please)
2015/07/09 22:35:34
done.
|
| + } else { |
| + m_fullScreenButton->setIsWanted(false); |
| + } |
| - refreshCastButtonVisibility(); |
| + refreshCastButtonVisibilityWithoutUpdate(); |
| makeOpaque(); |
| + changedControlSelections(); |
| } |
| LayoutObject* MediaControls::layoutObjectForTextTrackLayout() |
| @@ -207,7 +258,7 @@ LayoutObject* MediaControls::layoutObjectForTextTrackLayout() |
| void MediaControls::show() |
| { |
| makeOpaque(); |
| - m_panel->show(); |
| + m_panel->setIsWanted(true); |
| m_panel->setIsDisplayed(true); |
| if (m_overlayPlayButton) |
| m_overlayPlayButton->updateDisplayType(); |
| @@ -223,10 +274,10 @@ void MediaControls::mediaElementFocused() |
| void MediaControls::hide() |
| { |
| - m_panel->hide(); |
| + m_panel->setIsWanted(false); |
| m_panel->setIsDisplayed(false); |
| if (m_overlayPlayButton) |
| - m_overlayPlayButton->hide(); |
| + m_overlayPlayButton->setIsWanted(false); |
| } |
| void MediaControls::makeOpaque() |
| @@ -263,8 +314,10 @@ bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const |
| void MediaControls::playbackStarted() |
| { |
| - m_currentTimeDisplay->show(); |
| - m_durationDisplay->hide(); |
| + if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) { |
| + m_currentTimeDisplay->setIsWanted(true); |
| + m_durationDisplay->setIsWanted(false); |
| + } |
| updatePlayState(); |
| m_timeline->setPosition(mediaElement().currentTime()); |
| @@ -325,9 +378,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->setIsWanted(true); |
| + m_durationDisplay->setIsWanted(false); |
| } |
| // Allow the theme to format the time. |
| @@ -342,10 +395,18 @@ void MediaControls::updateVolume() |
| if (LayoutObject* layoutObject = m_muteButton->layoutObject()) |
| layoutObject->setShouldDoFullPaintInvalidation(); |
| - if (mediaElement().muted()) |
| + if (mediaElement().muted()) { |
| m_volumeSlider->setVolume(0); |
| - else |
| + // If the element is muted, then we want the unmute button. Otherwise, |
|
philipj_slow
2015/07/09 08:56:11
I think that if we're going to change anything abo
liberato (no reviews please)
2015/07/09 22:35:34
the latter one seems almost exactly what the code
philipj_slow
2015/07/09 23:18:36
FWIW, we unmute when pressing the overlay fullscre
liberato (no reviews please)
2015/07/14 22:10:36
added LayoutTests/media/video-controls-hidden-audi
|
| + // one can't unmute it. This makes a difference on android, where we |
| + // hide the mute button by default. crbug.com/467252 . |
| + if (mediaElement().hasAudio()) { |
| + m_muteButton->setIsWanted(true); |
| + } |
| + } else { |
| m_volumeSlider->setVolume(mediaElement().volume()); |
| + } |
| + |
| // Invalidate the volume slider because it paints differently according to volume. |
| if (LayoutObject* layoutObject = m_volumeSlider->layoutObject()) |
| layoutObject->setShouldDoFullPaintInvalidation(); |
| @@ -359,9 +420,9 @@ void MediaControls::changedClosedCaptionsVisibility() |
| void MediaControls::refreshClosedCaptionsButtonVisibility() |
| { |
| if (mediaElement().hasClosedCaptions()) |
| - m_toggleClosedCaptionsButton->show(); |
| + m_toggleClosedCaptionsButton->setIsWanted(true); |
|
philipj_slow
2015/07/09 08:56:11
Ditto.
liberato (no reviews please)
2015/07/09 22:35:34
Done.
|
| else |
| - m_toggleClosedCaptionsButton->hide(); |
| + m_toggleClosedCaptionsButton->setIsWanted(false); |
| } |
| static Element* elementFromCenter(Element& element) |
| @@ -376,14 +437,26 @@ static Element* elementFromCenter(Element& element) |
| void MediaControls::tryShowOverlayCastButton() |
| { |
| // The element needs to be shown to have its dimensions and position. |
| - m_overlayCastButton->show(); |
| + m_overlayCastButton->setIsWanted(true); |
| if (elementFromCenter(*m_overlayCastButton) != &mediaElement()) |
| - m_overlayCastButton->hide(); |
| + m_overlayCastButton->setIsWanted(false); |
| } |
| void MediaControls::refreshCastButtonVisibility() |
| { |
| + refreshCastButtonVisibilityWithoutUpdate(); |
| + changedControlSelections(); |
| +} |
| + |
| +void MediaControls::hideCastButtons() |
| +{ |
| + m_castButton->setIsWanted(false); |
| + m_overlayCastButton->setIsWanted(false); |
| +} |
| + |
| +void MediaControls::refreshCastButtonVisibilityWithoutUpdate() |
| +{ |
| 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 +464,29 @@ 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 |
|
philipj_slow
2015/07/09 08:56:10
s/bar/panel/ or "the button in the controls panel"
liberato (no reviews please)
2015/07/09 22:35:33
expanded comment.
|
| + // that updateControls...() won't change overlay cast button |
| + // visibility in the case where the cast button isn't wanted. |
| showOverlayCastButton(); |
| + m_castButton->setIsWanted(false); |
|
philipj_slow
2015/07/09 08:56:10
The mismatch between showOverlayCastButton() and m
liberato (no reviews please)
2015/07/09 22:35:34
yeah, i agree. changed.
liberato (no reviews please)
2015/07/14 22:10:36
it turns out that the right answer is tryShowOverl
|
| } 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_overlayCastButton->setIsWanted(false); |
| + m_castButton->setIsWanted(true); |
| + // Check that the cast button actually fits on the bar. For the |
| + // new ui, we let changedControlSelections() handle this. |
| + if ( !RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() |
| + && m_fullScreenButton->getBoundingClientRect()->right() > m_panel->getBoundingClientRect()->right()) { |
| + m_castButton->setIsWanted(false); |
| tryShowOverlayCastButton(); |
| } |
| } |
| } else { |
| - m_castButton->hide(); |
| - m_overlayCastButton->hide(); |
| + m_castButton->setIsWanted(false); |
| + m_overlayCastButton->setIsWanted(false); |
| } |
| + |
| + // do NOT updateControls...() here. |
|
philipj_slow
2015/07/09 08:56:11
This comment isn't needed IMHO.
liberato (no reviews please)
2015/07/09 22:35:34
Done.
|
| } |
| void MediaControls::showOverlayCastButton() |
| @@ -494,7 +576,7 @@ void MediaControls::hideMediaControlsTimerFired(Timer<MediaControls>*) |
| return; |
| makeTransparent(); |
| - m_overlayCastButton->hide(); |
| + m_overlayCastButton->setIsWanted(false); |
| } |
| void MediaControls::startHideMediaControlsTimer() |
| @@ -525,6 +607,81 @@ bool MediaControls::containsRelatedTarget(Event* event) |
| return contains(relatedTarget->toNode()); |
| } |
| +void MediaControls::notifyPanelWidthChanged(int panelWidth) |
| +{ |
| + // Don't bother to do any work if this matches the most recent panel |
| + // width, since we're called after layout. |
| + if (panelWidth == 0 || panelWidth == m_panelWidth) |
|
philipj_slow
2015/07/09 08:56:10
Shouldn't m_panelWidth still be updated? Seems sim
fs
2015/07/09 09:31:17
Yeah, if checking this at all, it's probably bette
liberato (no reviews please)
2015/07/09 12:10:56
i can remove the check here safely, but i can't ad
|
| + return; |
| + |
| + m_panelWidth = panelWidth; |
| + m_panelWidthChangedTimer.startOneShot(0, FROM_HERE); |
|
philipj_slow
2015/07/09 08:56:10
Given that this is called from LayoutMedia::layout
fs
2015/07/09 09:31:17
Correct on both accounts AFAIK.
liberato (no reviews please)
2015/07/09 12:10:57
to be clear: i'm about to go spelunking into layou
fs
2015/07/09 12:25:39
Well, it's essentially a QoI issue - there could (
philipj_slow
2015/07/10 14:51:58
So let's add a TODO that acknowledges that there's
liberato (no reviews please)
2015/07/14 22:10:36
Done.
|
| +} |
| + |
| +void MediaControls::changedControlSelections() |
| +{ |
| + int panelWidth = m_panel->clientWidth(); |
|
philipj_slow
2015/07/09 08:56:11
This may trigger a layout, is that intentional? It
liberato (no reviews please)
2015/07/09 22:35:34
i expected that it would avoid a bad frame, but tr
|
| + // Don't short-circuit update if the panel hasn't changed. The fit state |
| + // is a function of the controls we want, so recompute if we can. |
| + if (panelWidth == 0) |
| + return; |
| + |
| + m_panelWidth = panelWidth; |
| + computeWhichControlsFit(panelWidth); |
| +} |
| + |
| +void MediaControls::panelWidthChangedTimerFired(Timer<MediaControls>*) |
| +{ |
| + if (!m_panelWidth) |
| + return; |
| + |
| + computeWhichControlsFit(m_panelWidth); |
| +} |
| + |
| +void MediaControls::computeWhichControlsFit(int panelWidth) |
|
philipj_slow
2015/07/09 08:56:10
Seems like this doesn't need an argument, use m_pa
liberato (no reviews please)
2015/07/09 22:35:33
yeah, i had the same thought. i did it this way s
liberato (no reviews please)
2015/07/14 22:10:36
this does cause an extra bad frame, so i've left i
|
| +{ |
| + // 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. |
| + |
| + // 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++) { |
|
philipj_slow
2015/07/09 08:56:10
for (MediaControlElement* element : elements) at l
liberato (no reviews please)
2015/07/09 22:35:34
done, cool.
|
| + if (elements[i]->isWanted()) { |
| + if (usedWidth + elements[i]->minimumWidth() <= panelWidth) { |
| + elements[i]->setDoesFit(true); |
| + usedWidth += elements[i]->minimumWidth(); |
| + } else { |
| + elements[i]->setDoesFit(false); |
| + } |
| + } |
| + } |
| + |
| + // 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()) |
|
philipj_slow
2015/07/09 08:56:10
I think this and above are the only places where i
liberato (no reviews please)
2015/07/09 22:35:33
i've removed isShown(), but i don't see how to rem
philipj_slow
2015/07/09 23:18:37
Uh right, the loop above is also using isWanted(),
|
| + m_overlayCastButton->setIsWanted(true); |
| + else |
| + m_overlayCastButton->setIsWanted(false); |
| + } // else do not change overlay cast button state. |
|
philipj_slow
2015/07/09 08:56:11
Don't need this comment.
liberato (no reviews please)
2015/07/09 22:35:34
Done.
|
| +} |
| + |
| DEFINE_TRACE(MediaControls) |
| { |
| visitor->trace(m_mediaElement); |