Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. | 2 * Copyright (C) 2011, 2012 Apple Inc. All rights reserved. |
| 3 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. | 3 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 | 55 |
| 56 if (!mediaElement.hasVideo()) | 56 if (!mediaElement.hasVideo()) |
| 57 return false; | 57 return false; |
| 58 | 58 |
| 59 if (!Fullscreen::fullscreenEnabled(mediaElement.document())) | 59 if (!Fullscreen::fullscreenEnabled(mediaElement.document())) |
| 60 return false; | 60 return false; |
| 61 | 61 |
| 62 return true; | 62 return true; |
| 63 } | 63 } |
| 64 | 64 |
| 65 static bool preferHiddenVolumeControls(const Document& document) | |
| 66 { | |
| 67 return !document.settings() || document.settings()->preferHiddenVolumeContro ls(); | |
| 68 } | |
| 69 | |
| 70 class MediaControls::BatchedControlUpdate { | |
| 71 public: | |
| 72 BatchedControlUpdate(MediaControls* controls) : m_controls(controls) | |
| 73 { | |
| 74 m_controls->beginBatchUpdate(); | |
| 75 } | |
| 76 ~BatchedControlUpdate() | |
| 77 { | |
| 78 m_controls->endBatchUpdate(); | |
| 79 } | |
| 80 | |
| 81 private: | |
| 82 MediaControls* m_controls; | |
| 83 WTF_MAKE_NONCOPYABLE(BatchedControlUpdate); | |
|
philipj_slow
2015/08/04 11:54:53
This is usually before the public: bit, for some r
liberato (no reviews please)
2015/08/05 06:11:35
Done.
| |
| 84 }; | |
| 85 | |
| 65 MediaControls::MediaControls(HTMLMediaElement& mediaElement) | 86 MediaControls::MediaControls(HTMLMediaElement& mediaElement) |
| 66 : HTMLDivElement(mediaElement.document()) | 87 : HTMLDivElement(mediaElement.document()) |
| 67 , m_mediaElement(&mediaElement) | 88 , m_mediaElement(&mediaElement) |
| 68 , m_overlayEnclosure(nullptr) | 89 , m_overlayEnclosure(nullptr) |
| 69 , m_overlayPlayButton(nullptr) | 90 , m_overlayPlayButton(nullptr) |
| 70 , m_overlayCastButton(nullptr) | 91 , m_overlayCastButton(nullptr) |
| 71 , m_enclosure(nullptr) | 92 , m_enclosure(nullptr) |
| 72 , m_panel(nullptr) | 93 , m_panel(nullptr) |
| 73 , m_playButton(nullptr) | 94 , m_playButton(nullptr) |
| 74 , m_timeline(nullptr) | 95 , m_timeline(nullptr) |
| 75 , m_currentTimeDisplay(nullptr) | 96 , m_currentTimeDisplay(nullptr) |
| 76 , m_durationDisplay(nullptr) | 97 , m_durationDisplay(nullptr) |
| 77 , m_muteButton(nullptr) | 98 , m_muteButton(nullptr) |
| 78 , m_volumeSlider(nullptr) | 99 , m_volumeSlider(nullptr) |
| 79 , m_toggleClosedCaptionsButton(nullptr) | 100 , m_toggleClosedCaptionsButton(nullptr) |
| 80 , m_castButton(nullptr) | 101 , m_castButton(nullptr) |
| 81 , m_fullScreenButton(nullptr) | 102 , m_fullScreenButton(nullptr) |
| 82 , m_hideMediaControlsTimer(this, &MediaControls::hideMediaControlsTimerFired ) | 103 , m_hideMediaControlsTimer(this, &MediaControls::hideMediaControlsTimerFired ) |
| 83 , m_hideTimerBehaviorFlags(IgnoreNone) | 104 , m_hideTimerBehaviorFlags(IgnoreNone) |
| 84 , m_isMouseOverControls(false) | 105 , m_isMouseOverControls(false) |
| 85 , m_isPausedForScrubbing(false) | 106 , m_isPausedForScrubbing(false) |
| 107 , m_panelWidthChangedTimer(this, &MediaControls::panelWidthChangedTimerFired ) | |
| 108 , m_panelWidth(0) | |
| 109 , m_allowHiddenVolumeControls(RuntimeEnabledFeatures::newMediaPlaybackUiEnab led()) | |
| 110 , m_keepMuteButton(false) | |
| 111 , m_batchDepth(0) | |
| 86 { | 112 { |
| 87 } | 113 } |
| 88 | 114 |
| 89 PassRefPtrWillBeRawPtr<MediaControls> MediaControls::create(HTMLMediaElement& me diaElement) | 115 PassRefPtrWillBeRawPtr<MediaControls> MediaControls::create(HTMLMediaElement& me diaElement) |
| 90 { | 116 { |
| 91 RefPtrWillBeRawPtr<MediaControls> controls = adoptRefWillBeNoop(new MediaCon trols(mediaElement)); | 117 RefPtrWillBeRawPtr<MediaControls> controls = adoptRefWillBeNoop(new MediaCon trols(mediaElement)); |
| 92 controls->setShadowPseudoId(AtomicString("-webkit-media-controls", AtomicStr ing::ConstructFromLiteral)); | 118 controls->setShadowPseudoId(AtomicString("-webkit-media-controls", AtomicStr ing::ConstructFromLiteral)); |
| 93 controls->initializeControls(); | 119 controls->initializeControls(); |
| 94 return controls.release(); | 120 return controls.release(); |
| 95 } | 121 } |
| 96 | 122 |
| 97 // The media controls DOM structure looks like: | 123 // The media controls DOM structure looks like: |
| 98 // | 124 // |
| 99 // MediaControls (-webkit-media-controls) | 125 // MediaControls (-webkit-media-controls) |
| 100 // +-MediaControlOverlayEnclosureElement (-webkit-media-controls-o verlay-enclosure) | 126 // +-MediaControlOverlayEnclosureElement (-webkit-media-controls-o verlay-enclosure) |
| 101 // | +-MediaControlOverlayPlayButtonElement (-webkit-media-controls-o verlay-play-button) | 127 // | +-MediaControlOverlayPlayButtonElement (-webkit-media-controls-o verlay-play-button) |
| 102 // | | {if mediaControlsOverlayPlayButtonEnabled} | 128 // | | {if mediaControlsOverlayPlayButtonEnabled} |
| 103 // | \-MediaControlCastButtonElement (-internal-media-controls -overlay-cast-button) | 129 // | \-MediaControlCastButtonElement (-internal-media-controls -overlay-cast-button) |
| 104 // \-MediaControlPanelEnclosureElement (-webkit-media-controls-e nclosure) | 130 // \-MediaControlPanelEnclosureElement (-webkit-media-controls-e nclosure) |
| 105 // \-MediaControlPanelElement (-webkit-media-controls-p anel) | 131 // \-MediaControlPanelElement (-webkit-media-controls-p anel) |
| 106 // +-MediaControlPlayButtonElement (-webkit-media-controls-p lay-button) | 132 // +-MediaControlPlayButtonElement (-webkit-media-controls-p lay-button) |
| 133 // | {if !RTE::newMediaPlaybackUi()} | |
| 107 // +-MediaControlTimelineElement (-webkit-media-controls-t imeline) | 134 // +-MediaControlTimelineElement (-webkit-media-controls-t imeline) |
| 108 // +-MediaControlCurrentTimeDisplayElement (-webkit-media-controls-c urrent-time-display) | 135 // +-MediaControlCurrentTimeDisplayElement (-webkit-media-controls-c urrent-time-display) |
| 109 // +-MediaControlTimeRemainingDisplayElement (-webkit-media-controls-t ime-remaining-display) | 136 // +-MediaControlTimeRemainingDisplayElement (-webkit-media-controls-t ime-remaining-display) |
| 137 // | {if RTE::newMediaPlaybackUi()} | |
| 138 // +-MediaControlTimelineElement (-webkit-media-controls-t imeline) | |
| 110 // +-MediaControlMuteButtonElement (-webkit-media-controls-m ute-button) | 139 // +-MediaControlMuteButtonElement (-webkit-media-controls-m ute-button) |
| 111 // +-MediaControlVolumeSliderElement (-webkit-media-controls-v olume-slider) | 140 // +-MediaControlVolumeSliderElement (-webkit-media-controls-v olume-slider) |
| 112 // +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-t oggle-closed-captions-button) | 141 // +-MediaControlToggleClosedCaptionsButtonElement (-webkit-media-controls-t oggle-closed-captions-button) |
| 113 // +-MediaControlCastButtonElement (-internal-media-controls -cast-button) | 142 // +-MediaControlCastButtonElement (-internal-media-controls -cast-button) |
| 114 // \-MediaControlFullscreenButtonElement (-webkit-media-controls-f ullscreen-button) | 143 // \-MediaControlFullscreenButtonElement (-webkit-media-controls-f ullscreen-button) |
| 115 void MediaControls::initializeControls() | 144 void MediaControls::initializeControls() |
| 116 { | 145 { |
| 146 const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled(); | |
| 117 RefPtrWillBeRawPtr<MediaControlOverlayEnclosureElement> overlayEnclosure = M ediaControlOverlayEnclosureElement::create(*this); | 147 RefPtrWillBeRawPtr<MediaControlOverlayEnclosureElement> overlayEnclosure = M ediaControlOverlayEnclosureElement::create(*this); |
| 118 | 148 |
| 119 if (document().settings() && document().settings()->mediaControlsOverlayPlay ButtonEnabled()) { | 149 if (document().settings() && document().settings()->mediaControlsOverlayPlay ButtonEnabled()) { |
| 120 RefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> overlayPlayButt on = MediaControlOverlayPlayButtonElement::create(*this); | 150 RefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> overlayPlayButt on = MediaControlOverlayPlayButtonElement::create(*this); |
| 121 m_overlayPlayButton = overlayPlayButton.get(); | 151 m_overlayPlayButton = overlayPlayButton.get(); |
| 122 overlayEnclosure->appendChild(overlayPlayButton.release()); | 152 overlayEnclosure->appendChild(overlayPlayButton.release()); |
| 123 } | 153 } |
| 124 | 154 |
| 125 RefPtrWillBeRawPtr<MediaControlCastButtonElement> overlayCastButton = MediaC ontrolCastButtonElement::create(*this, true); | 155 RefPtrWillBeRawPtr<MediaControlCastButtonElement> overlayCastButton = MediaC ontrolCastButtonElement::create(*this, true); |
| 126 m_overlayCastButton = overlayCastButton.get(); | 156 m_overlayCastButton = overlayCastButton.get(); |
| 127 overlayEnclosure->appendChild(overlayCastButton.release()); | 157 overlayEnclosure->appendChild(overlayCastButton.release()); |
| 128 | 158 |
| 129 m_overlayEnclosure = overlayEnclosure.get(); | 159 m_overlayEnclosure = overlayEnclosure.get(); |
| 130 appendChild(overlayEnclosure.release()); | 160 appendChild(overlayEnclosure.release()); |
| 131 | 161 |
| 132 // Create an enclosing element for the panel so we can visually offset the c ontrols correctly. | 162 // Create an enclosing element for the panel so we can visually offset the c ontrols correctly. |
| 133 RefPtrWillBeRawPtr<MediaControlPanelEnclosureElement> enclosure = MediaContr olPanelEnclosureElement::create(*this); | 163 RefPtrWillBeRawPtr<MediaControlPanelEnclosureElement> enclosure = MediaContr olPanelEnclosureElement::create(*this); |
| 134 | 164 |
| 135 RefPtrWillBeRawPtr<MediaControlPanelElement> panel = MediaControlPanelElemen t::create(*this); | 165 RefPtrWillBeRawPtr<MediaControlPanelElement> panel = MediaControlPanelElemen t::create(*this); |
| 136 | 166 |
| 137 RefPtrWillBeRawPtr<MediaControlPlayButtonElement> playButton = MediaControlP layButtonElement::create(*this); | 167 RefPtrWillBeRawPtr<MediaControlPlayButtonElement> playButton = MediaControlP layButtonElement::create(*this); |
| 138 m_playButton = playButton.get(); | 168 m_playButton = playButton.get(); |
| 139 panel->appendChild(playButton.release()); | 169 panel->appendChild(playButton.release()); |
| 140 | 170 |
| 141 RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = MediaControlTimel ineElement::create(*this); | 171 RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = MediaControlTimel ineElement::create(*this); |
| 142 m_timeline = timeline.get(); | 172 m_timeline = timeline.get(); |
| 143 panel->appendChild(timeline.release()); | 173 // In old UX, timeline is before the time / duration text. |
| 174 if (!useNewUi) | |
| 175 panel->appendChild(timeline.release()); | |
| 176 // else we will attach it later. | |
| 144 | 177 |
| 145 RefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(*this); | 178 RefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(*this); |
| 146 m_currentTimeDisplay = currentTimeDisplay.get(); | 179 m_currentTimeDisplay = currentTimeDisplay.get(); |
| 147 m_currentTimeDisplay->hide(); | 180 m_currentTimeDisplay->setIsWanted(useNewUi); |
| 148 panel->appendChild(currentTimeDisplay.release()); | 181 panel->appendChild(currentTimeDisplay.release()); |
| 149 | 182 |
| 150 RefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> durationDisplay = MediaControlTimeRemainingDisplayElement::create(*this); | 183 RefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> durationDisplay = MediaControlTimeRemainingDisplayElement::create(*this); |
| 151 m_durationDisplay = durationDisplay.get(); | 184 m_durationDisplay = durationDisplay.get(); |
| 152 panel->appendChild(durationDisplay.release()); | 185 panel->appendChild(durationDisplay.release()); |
| 153 | 186 |
| 187 // Timeline is after the time / duration text if newMediaPlaybackUiEnabled. | |
| 188 if (useNewUi) | |
| 189 panel->appendChild(timeline.release()); | |
| 190 | |
| 154 RefPtrWillBeRawPtr<MediaControlMuteButtonElement> muteButton = MediaControlM uteButtonElement::create(*this); | 191 RefPtrWillBeRawPtr<MediaControlMuteButtonElement> muteButton = MediaControlM uteButtonElement::create(*this); |
| 155 m_muteButton = muteButton.get(); | 192 m_muteButton = muteButton.get(); |
| 156 panel->appendChild(muteButton.release()); | 193 panel->appendChild(muteButton.release()); |
| 194 if (m_allowHiddenVolumeControls && preferHiddenVolumeControls(document())) | |
| 195 m_muteButton->setIsWanted(false); | |
| 157 | 196 |
| 158 RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = MediaControlVol umeSliderElement::create(*this); | 197 RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = MediaControlVol umeSliderElement::create(*this); |
| 159 m_volumeSlider = slider.get(); | 198 m_volumeSlider = slider.get(); |
| 160 panel->appendChild(slider.release()); | 199 panel->appendChild(slider.release()); |
| 200 if (m_allowHiddenVolumeControls && preferHiddenVolumeControls(document())) | |
| 201 m_volumeSlider->setIsWanted(false); | |
| 161 | 202 |
| 162 RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClos edCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(*this); | 203 RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClos edCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(*this); |
| 163 m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); | 204 m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); |
| 164 panel->appendChild(toggleClosedCaptionsButton.release()); | 205 panel->appendChild(toggleClosedCaptionsButton.release()); |
| 165 | 206 |
| 166 RefPtrWillBeRawPtr<MediaControlCastButtonElement> castButton = MediaControlC astButtonElement::create(*this, false); | 207 RefPtrWillBeRawPtr<MediaControlCastButtonElement> castButton = MediaControlC astButtonElement::create(*this, false); |
| 167 m_castButton = castButton.get(); | 208 m_castButton = castButton.get(); |
| 168 panel->appendChild(castButton.release()); | 209 panel->appendChild(castButton.release()); |
| 169 | 210 |
| 170 RefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> fullscreenButton = M ediaControlFullscreenButtonElement::create(*this); | 211 RefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> fullscreenButton = M ediaControlFullscreenButtonElement::create(*this); |
| 171 m_fullScreenButton = fullscreenButton.get(); | 212 m_fullScreenButton = fullscreenButton.get(); |
| 172 panel->appendChild(fullscreenButton.release()); | 213 panel->appendChild(fullscreenButton.release()); |
| 173 | 214 |
| 174 m_panel = panel.get(); | 215 m_panel = panel.get(); |
| 175 enclosure->appendChild(panel.release()); | 216 enclosure->appendChild(panel.release()); |
| 176 | 217 |
| 177 m_enclosure = enclosure.get(); | 218 m_enclosure = enclosure.get(); |
| 178 appendChild(enclosure.release()); | 219 appendChild(enclosure.release()); |
| 179 } | 220 } |
| 180 | 221 |
| 181 void MediaControls::reset() | 222 void MediaControls::reset() |
| 182 { | 223 { |
| 183 double duration = mediaElement().duration(); | 224 const bool useNewUi = RuntimeEnabledFeatures::newMediaPlaybackUiEnabled(); |
| 225 BatchedControlUpdate batch(this); | |
| 226 | |
| 227 m_allowHiddenVolumeControls = useNewUi; | |
| 228 m_keepMuteButton = false; | |
| 229 | |
| 230 const double duration = mediaElement().duration(); | |
| 184 m_durationDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsTime (duration), ASSERT_NO_EXCEPTION); | 231 m_durationDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsTime (duration), ASSERT_NO_EXCEPTION); |
| 185 m_durationDisplay->setCurrentValue(duration); | 232 m_durationDisplay->setCurrentValue(duration); |
| 186 | 233 |
| 234 if (useNewUi) { | |
| 235 // Show everything that we might hide. | |
| 236 // If we don't have a duration, then mark it to be hidden. For the | |
| 237 // old UI case, want / don't want is the same as show / hide since | |
| 238 // it is never marked as not fitting. | |
| 239 m_durationDisplay->setIsWanted(std::isfinite(duration)); | |
| 240 m_currentTimeDisplay->setIsWanted(true); | |
| 241 m_timeline->setIsWanted(true); | |
| 242 } | |
| 243 | |
| 187 updatePlayState(); | 244 updatePlayState(); |
| 188 | 245 |
| 189 updateCurrentTimeDisplay(); | 246 updateCurrentTimeDisplay(); |
| 190 | 247 |
| 191 m_timeline->setDuration(duration); | 248 m_timeline->setDuration(duration); |
| 192 m_timeline->setPosition(mediaElement().currentTime()); | 249 m_timeline->setPosition(mediaElement().currentTime()); |
| 193 | 250 |
| 194 if (!mediaElement().hasAudio()) | |
| 195 m_volumeSlider->hide(); | |
| 196 else | |
| 197 m_volumeSlider->show(); | |
| 198 updateVolume(); | 251 updateVolume(); |
| 199 | 252 |
| 200 refreshClosedCaptionsButtonVisibility(); | 253 refreshClosedCaptionsButtonVisibility(); |
| 201 | 254 |
| 202 if (shouldShowFullscreenButton(mediaElement())) | 255 m_fullScreenButton->setIsWanted(shouldShowFullscreenButton(mediaElement())); |
| 203 m_fullScreenButton->show(); | |
| 204 else | |
| 205 m_fullScreenButton->hide(); | |
| 206 | 256 |
| 207 refreshCastButtonVisibility(); | 257 refreshCastButtonVisibilityWithoutUpdate(); |
| 208 makeOpaque(); | 258 makeOpaque(); |
| 259 | |
| 260 // Set the panel width here, and force a layout, before the controls update . | |
| 261 m_panelWidth = m_panel->clientWidth(); | |
| 209 } | 262 } |
| 210 | 263 |
| 211 LayoutObject* MediaControls::layoutObjectForTextTrackLayout() | 264 LayoutObject* MediaControls::layoutObjectForTextTrackLayout() |
| 212 { | 265 { |
| 213 return m_panel->layoutObject(); | 266 return m_panel->layoutObject(); |
| 214 } | 267 } |
| 215 | 268 |
| 216 void MediaControls::show() | 269 void MediaControls::show() |
| 217 { | 270 { |
| 218 makeOpaque(); | 271 makeOpaque(); |
| 219 m_panel->show(); | 272 m_panel->setIsWanted(true); |
| 220 m_panel->setIsDisplayed(true); | 273 m_panel->setIsDisplayed(true); |
| 221 if (m_overlayPlayButton) | 274 if (m_overlayPlayButton) |
| 222 m_overlayPlayButton->updateDisplayType(); | 275 m_overlayPlayButton->updateDisplayType(); |
| 223 } | 276 } |
| 224 | 277 |
| 225 void MediaControls::mediaElementFocused() | 278 void MediaControls::mediaElementFocused() |
| 226 { | 279 { |
| 227 if (mediaElement().shouldShowControls()) { | 280 if (mediaElement().shouldShowControls()) { |
| 228 show(); | 281 show(); |
| 229 resetHideMediaControlsTimer(); | 282 resetHideMediaControlsTimer(); |
| 230 } | 283 } |
| 231 } | 284 } |
| 232 | 285 |
| 233 void MediaControls::hide() | 286 void MediaControls::hide() |
| 234 { | 287 { |
| 235 m_panel->hide(); | 288 m_panel->setIsWanted(false); |
| 236 m_panel->setIsDisplayed(false); | 289 m_panel->setIsDisplayed(false); |
| 237 if (m_overlayPlayButton) | 290 if (m_overlayPlayButton) |
| 238 m_overlayPlayButton->hide(); | 291 m_overlayPlayButton->setIsWanted(false); |
| 239 } | 292 } |
| 240 | 293 |
| 241 void MediaControls::makeOpaque() | 294 void MediaControls::makeOpaque() |
| 242 { | 295 { |
| 243 m_panel->makeOpaque(); | 296 m_panel->makeOpaque(); |
| 244 } | 297 } |
| 245 | 298 |
| 246 void MediaControls::makeTransparent() | 299 void MediaControls::makeTransparent() |
| 247 { | 300 { |
| 248 m_panel->makeTransparent(); | 301 m_panel->makeTransparent(); |
| 302 m_overlayCastButton->setIsWanted(false); | |
| 249 } | 303 } |
| 250 | 304 |
| 251 bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const | 305 bool MediaControls::shouldHideMediaControls(unsigned behaviorFlags) const |
| 252 { | 306 { |
| 253 // Never hide for a media element without visual representation. | 307 // Never hide for a media element without visual representation. |
| 254 if (!mediaElement().hasVideo() || mediaElement().isPlayingRemotely()) | 308 if (!mediaElement().hasVideo() || mediaElement().isPlayingRemotely()) |
| 255 return false; | 309 return false; |
| 256 // Don't hide if the mouse is over the controls. | 310 // Don't hide if the mouse is over the controls. |
| 257 const bool ignoreControlsHover = behaviorFlags & IgnoreControlsHover; | 311 const bool ignoreControlsHover = behaviorFlags & IgnoreControlsHover; |
| 258 if (!ignoreControlsHover && m_panel->hovered()) | 312 if (!ignoreControlsHover && m_panel->hovered()) |
| 259 return false; | 313 return false; |
| 260 // Don't hide if the mouse is over the video area. | 314 // Don't hide if the mouse is over the video area. |
| 261 const bool ignoreVideoHover = behaviorFlags & IgnoreVideoHover; | 315 const bool ignoreVideoHover = behaviorFlags & IgnoreVideoHover; |
| 262 if (!ignoreVideoHover && m_isMouseOverControls) | 316 if (!ignoreVideoHover && m_isMouseOverControls) |
| 263 return false; | 317 return false; |
| 264 // Don't hide if focus is on the HTMLMediaElement or within the | 318 // Don't hide if focus is on the HTMLMediaElement or within the |
| 265 // controls/shadow tree. (Perform the checks separately to avoid going | 319 // controls/shadow tree. (Perform the checks separately to avoid going |
| 266 // through all the potential ancestor hosts for the focused element.) | 320 // through all the potential ancestor hosts for the focused element.) |
| 267 const bool ignoreFocus = behaviorFlags & IgnoreFocus; | 321 const bool ignoreFocus = behaviorFlags & IgnoreFocus; |
| 268 if (!ignoreFocus && (mediaElement().focused() || contains(document().focused Element()))) | 322 if (!ignoreFocus && (mediaElement().focused() || contains(document().focused Element()))) |
| 269 return false; | 323 return false; |
| 270 return true; | 324 return true; |
| 271 } | 325 } |
| 272 | 326 |
| 273 void MediaControls::playbackStarted() | 327 void MediaControls::playbackStarted() |
| 274 { | 328 { |
| 275 m_currentTimeDisplay->show(); | 329 BatchedControlUpdate batch(this); |
| 276 m_durationDisplay->hide(); | 330 |
| 331 if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) { | |
| 332 m_currentTimeDisplay->setIsWanted(true); | |
| 333 m_durationDisplay->setIsWanted(false); | |
| 334 } | |
| 277 | 335 |
| 278 updatePlayState(); | 336 updatePlayState(); |
| 279 m_timeline->setPosition(mediaElement().currentTime()); | 337 m_timeline->setPosition(mediaElement().currentTime()); |
| 280 updateCurrentTimeDisplay(); | 338 updateCurrentTimeDisplay(); |
| 281 | 339 |
| 282 startHideMediaControlsTimer(); | 340 startHideMediaControlsTimer(); |
| 283 } | 341 } |
| 284 | 342 |
| 285 void MediaControls::playbackProgressed() | 343 void MediaControls::playbackProgressed() |
| 286 { | 344 { |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 327 mediaElement().togglePlayState(); | 385 mediaElement().togglePlayState(); |
| 328 } | 386 } |
| 329 } | 387 } |
| 330 | 388 |
| 331 void MediaControls::updateCurrentTimeDisplay() | 389 void MediaControls::updateCurrentTimeDisplay() |
| 332 { | 390 { |
| 333 double now = mediaElement().currentTime(); | 391 double now = mediaElement().currentTime(); |
| 334 double duration = mediaElement().duration(); | 392 double duration = mediaElement().duration(); |
| 335 | 393 |
| 336 // After seek, hide duration display and show current time. | 394 // After seek, hide duration display and show current time. |
| 337 if (now > 0) { | 395 if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() && now > 0) { |
| 338 m_currentTimeDisplay->show(); | 396 BatchedControlUpdate batch(this); |
| 339 m_durationDisplay->hide(); | 397 m_currentTimeDisplay->setIsWanted(true); |
| 398 m_durationDisplay->setIsWanted(false); | |
| 340 } | 399 } |
| 341 | 400 |
| 342 // Allow the theme to format the time. | 401 // Allow the theme to format the time. |
| 343 m_currentTimeDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsC urrentTime(now, duration), IGNORE_EXCEPTION); | 402 m_currentTimeDisplay->setInnerText(LayoutTheme::theme().formatMediaControlsC urrentTime(now, duration), IGNORE_EXCEPTION); |
| 344 m_currentTimeDisplay->setCurrentValue(now); | 403 m_currentTimeDisplay->setCurrentValue(now); |
| 345 } | 404 } |
| 346 | 405 |
| 347 void MediaControls::updateVolume() | 406 void MediaControls::updateVolume() |
| 348 { | 407 { |
| 349 m_muteButton->updateDisplayType(); | 408 m_muteButton->updateDisplayType(); |
| 350 // Invalidate the mute button because it paints differently according to vol ume. | 409 // Invalidate the mute button because it paints differently according to vol ume. |
| 351 if (LayoutObject* layoutObject = m_muteButton->layoutObject()) | 410 if (LayoutObject* layoutObject = m_muteButton->layoutObject()) |
| 352 layoutObject->setShouldDoFullPaintInvalidation(); | 411 layoutObject->setShouldDoFullPaintInvalidation(); |
| 353 | 412 |
| 354 if (mediaElement().muted()) | 413 if (mediaElement().muted()) |
| 355 m_volumeSlider->setVolume(0); | 414 m_volumeSlider->setVolume(0); |
| 356 else | 415 else |
| 357 m_volumeSlider->setVolume(mediaElement().volume()); | 416 m_volumeSlider->setVolume(mediaElement().volume()); |
| 417 | |
| 418 // Update the visibility of our audio elements. | |
| 419 // We never want the volume slider if there's no audio. | |
| 420 // If there is audio, then we want it unless hiding audio is enabled and | |
| 421 // we prefer to hide it. | |
| 422 BatchedControlUpdate batch(this); | |
| 423 m_volumeSlider->setIsWanted(mediaElement().hasAudio() | |
| 424 && !(m_allowHiddenVolumeControls && preferHiddenVolumeControls(document( )))); | |
| 425 | |
| 426 // The mute button is a little more complicated. If enableNewMediaPlaybackU i | |
| 427 // is true, then we choose to hide or show the mute button to save space. | |
| 428 // If enableNew* is not set, then we never touch the mute button, and | |
| 429 // instead leave it to the CSS. | |
| 430 // Note that this is why m_allowHiddenVolumeControls isn't rolled into prefe r...(). | |
| 431 if (m_allowHiddenVolumeControls) { | |
| 432 // If there is no audio track, then hide the mute button. If there | |
| 433 // is an audio track, then we always show the mute button unless | |
| 434 // we prefer to hide it and the media isn't muted. If it's muted, | |
| 435 // then we show it to let the user unmute it. In this case, we don't | |
| 436 // want to re-hide the mute button later. | |
| 437 m_keepMuteButton |= mediaElement().muted(); | |
| 438 m_muteButton->setIsWanted(mediaElement().hasAudio() | |
| 439 && (!preferHiddenVolumeControls(document()) || m_keepMuteButton)); | |
| 440 } | |
| 441 | |
| 358 // Invalidate the volume slider because it paints differently according to v olume. | 442 // Invalidate the volume slider because it paints differently according to v olume. |
| 359 if (LayoutObject* layoutObject = m_volumeSlider->layoutObject()) | 443 if (LayoutObject* layoutObject = m_volumeSlider->layoutObject()) |
| 360 layoutObject->setShouldDoFullPaintInvalidation(); | 444 layoutObject->setShouldDoFullPaintInvalidation(); |
| 361 } | 445 } |
| 362 | 446 |
| 363 void MediaControls::changedClosedCaptionsVisibility() | 447 void MediaControls::changedClosedCaptionsVisibility() |
| 364 { | 448 { |
| 365 m_toggleClosedCaptionsButton->updateDisplayType(); | 449 m_toggleClosedCaptionsButton->updateDisplayType(); |
| 366 } | 450 } |
| 367 | 451 |
| 368 void MediaControls::refreshClosedCaptionsButtonVisibility() | 452 void MediaControls::refreshClosedCaptionsButtonVisibility() |
| 369 { | 453 { |
| 370 if (mediaElement().hasClosedCaptions()) | 454 m_toggleClosedCaptionsButton->setIsWanted(mediaElement().hasClosedCaptions() ); |
| 371 m_toggleClosedCaptionsButton->show(); | 455 BatchedControlUpdate batch(this); |
| 372 else | |
| 373 m_toggleClosedCaptionsButton->hide(); | |
| 374 } | 456 } |
| 375 | 457 |
| 376 static Element* elementFromCenter(Element& element) | 458 static Element* elementFromCenter(Element& element) |
| 377 { | 459 { |
| 378 ClientRect* clientRect = element.getBoundingClientRect(); | 460 ClientRect* clientRect = element.getBoundingClientRect(); |
| 379 int centerX = static_cast<int>((clientRect->left() + clientRect->right()) / 2); | 461 int centerX = static_cast<int>((clientRect->left() + clientRect->right()) / 2); |
| 380 int centerY = static_cast<int>((clientRect->top() + clientRect->bottom()) / 2); | 462 int centerY = static_cast<int>((clientRect->top() + clientRect->bottom()) / 2); |
| 381 | 463 |
| 382 return element.document().elementFromPoint(centerX , centerY); | 464 return element.document().elementFromPoint(centerX , centerY); |
| 383 } | 465 } |
| 384 | 466 |
| 385 void MediaControls::tryShowOverlayCastButton() | 467 void MediaControls::tryShowOverlayCastButton() |
| 386 { | 468 { |
| 387 // The element needs to be shown to have its dimensions and position. | 469 // The element needs to be shown to have its dimensions and position. |
| 388 m_overlayCastButton->show(); | 470 m_overlayCastButton->setIsWanted(true); |
| 389 | |
| 390 if (elementFromCenter(*m_overlayCastButton) != &mediaElement()) | 471 if (elementFromCenter(*m_overlayCastButton) != &mediaElement()) |
| 391 m_overlayCastButton->hide(); | 472 m_overlayCastButton->setIsWanted(false); |
| 392 } | 473 } |
| 393 | 474 |
| 394 void MediaControls::refreshCastButtonVisibility() | 475 void MediaControls::refreshCastButtonVisibility() |
| 395 { | 476 { |
| 477 refreshCastButtonVisibilityWithoutUpdate(); | |
| 478 BatchedControlUpdate batch(this); | |
| 479 } | |
| 480 | |
| 481 void MediaControls::refreshCastButtonVisibilityWithoutUpdate() | |
| 482 { | |
| 396 if (mediaElement().hasRemoteRoutes()) { | 483 if (mediaElement().hasRemoteRoutes()) { |
| 397 // The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which | 484 // The reason for the autoplay test is that some pages (e.g. vimeo.com) have an autoplay background video, which |
| 398 // doesn't autoplay on Chrome for Android (we prevent it) so starts paus ed. In such cases we don't want to automatically | 485 // doesn't autoplay on Chrome for Android (we prevent it) so starts paus ed. In such cases we don't want to automatically |
| 399 // show the cast button, since it looks strange and is unlikely to corre spond with anything the user wants to do. | 486 // show the cast button, since it looks strange and is unlikely to corre spond with anything the user wants to do. |
| 400 // If a user does want to cast a paused autoplay video then they can sti ll do so by touching or clicking on the | 487 // If a user does want to cast a paused autoplay video then they can sti ll do so by touching or clicking on the |
| 401 // video, which will cause the cast button to appear. | 488 // video, which will cause the cast button to appear. |
| 402 if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() & & mediaElement().paused()) { | 489 if (!mediaElement().shouldShowControls() && !mediaElement().autoplay() & & mediaElement().paused()) { |
| 403 showOverlayCastButton(); | 490 // Note that this is a case where we add the overlay cast button |
| 491 // without wanting the panel cast button. We depend on the fact | |
| 492 // that computeWhichControlsFit() won't change overlay cast button | |
| 493 // visibility in the case where the cast button isn't wanted. | |
| 494 // We don't call compute...() here, but it will be called as | |
| 495 // non-cast changes (e.g., resize) occur. If the panel button | |
| 496 // is shown, however, compute...() will take control of the | |
| 497 // overlay cast button if it needs to hide it from the panel. | |
| 498 tryShowOverlayCastButton(); | |
| 499 m_castButton->setIsWanted(false); | |
| 404 } else if (mediaElement().shouldShowControls()) { | 500 } else if (mediaElement().shouldShowControls()) { |
| 405 m_overlayCastButton->hide(); | 501 m_overlayCastButton->setIsWanted(false); |
| 406 m_castButton->show(); | 502 m_castButton->setIsWanted(true); |
| 407 // Check that the cast button actually fits on the bar. | 503 // Check that the cast button actually fits on the bar. For the |
| 408 if (m_fullScreenButton->getBoundingClientRect()->right() > m_panel-> getBoundingClientRect()->right()) { | 504 // newMediaPlaybackUiEnabled case, we let computeWhichControlsFit() |
| 409 m_castButton->hide(); | 505 // handle this. |
| 506 if ( !RuntimeEnabledFeatures::newMediaPlaybackUiEnabled() | |
| 507 && m_fullScreenButton->getBoundingClientRect()->right() > m_pane l->getBoundingClientRect()->right()) { | |
| 508 m_castButton->setIsWanted(false); | |
| 410 tryShowOverlayCastButton(); | 509 tryShowOverlayCastButton(); |
| 411 } | 510 } |
| 412 } | 511 } |
| 413 } else { | 512 } else { |
| 414 m_castButton->hide(); | 513 m_castButton->setIsWanted(false); |
| 415 m_overlayCastButton->hide(); | 514 m_overlayCastButton->setIsWanted(false); |
| 416 } | 515 } |
| 417 } | 516 } |
| 418 | 517 |
| 419 void MediaControls::showOverlayCastButton() | 518 void MediaControls::showOverlayCastButton() |
| 420 { | 519 { |
| 421 tryShowOverlayCastButton(); | 520 tryShowOverlayCastButton(); |
| 422 resetHideMediaControlsTimer(); | 521 resetHideMediaControlsTimer(); |
| 423 } | 522 } |
| 424 | 523 |
| 425 void MediaControls::enteredFullscreen() | 524 void MediaControls::enteredFullscreen() |
| (...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 496 unsigned behaviorFlags = m_hideTimerBehaviorFlags | IgnoreFocus | IgnoreVide oHover; | 595 unsigned behaviorFlags = m_hideTimerBehaviorFlags | IgnoreFocus | IgnoreVide oHover; |
| 497 m_hideTimerBehaviorFlags = IgnoreNone; | 596 m_hideTimerBehaviorFlags = IgnoreNone; |
| 498 | 597 |
| 499 if (mediaElement().togglePlayStateWillPlay()) | 598 if (mediaElement().togglePlayStateWillPlay()) |
| 500 return; | 599 return; |
| 501 | 600 |
| 502 if (!shouldHideMediaControls(behaviorFlags)) | 601 if (!shouldHideMediaControls(behaviorFlags)) |
| 503 return; | 602 return; |
| 504 | 603 |
| 505 makeTransparent(); | 604 makeTransparent(); |
| 506 m_overlayCastButton->hide(); | |
| 507 } | 605 } |
| 508 | 606 |
| 509 void MediaControls::startHideMediaControlsTimer() | 607 void MediaControls::startHideMediaControlsTimer() |
| 510 { | 608 { |
| 511 m_hideMediaControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingMe diaControls, FROM_HERE); | 609 m_hideMediaControlsTimer.startOneShot(timeWithoutMouseMovementBeforeHidingMe diaControls, FROM_HERE); |
| 512 } | 610 } |
| 513 | 611 |
| 514 void MediaControls::stopHideMediaControlsTimer() | 612 void MediaControls::stopHideMediaControlsTimer() |
| 515 { | 613 { |
| 516 m_hideMediaControlsTimer.stop(); | 614 m_hideMediaControlsTimer.stop(); |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 527 bool MediaControls::containsRelatedTarget(Event* event) | 625 bool MediaControls::containsRelatedTarget(Event* event) |
| 528 { | 626 { |
| 529 if (!event->isMouseEvent()) | 627 if (!event->isMouseEvent()) |
| 530 return false; | 628 return false; |
| 531 EventTarget* relatedTarget = toMouseEvent(event)->relatedTarget(); | 629 EventTarget* relatedTarget = toMouseEvent(event)->relatedTarget(); |
| 532 if (!relatedTarget) | 630 if (!relatedTarget) |
| 533 return false; | 631 return false; |
| 534 return contains(relatedTarget->toNode()); | 632 return contains(relatedTarget->toNode()); |
| 535 } | 633 } |
| 536 | 634 |
| 635 void MediaControls::notifyPanelWidthChanged(const LayoutUnit& newWidth) | |
| 636 { | |
| 637 // Don't bother to do any work if this matches the most recent panel | |
| 638 // width, since we're called after layout. | |
| 639 // Note that this code permits a bad frame on resize, since it is | |
| 640 // run after the relayout / paint happens. It would be great to improve | |
| 641 // this, but it would be even greater to move this code entirely to | |
| 642 // JS and fix it there. | |
| 643 const int panelWidth = newWidth.toInt(); | |
| 644 | |
| 645 if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) | |
| 646 return; | |
| 647 | |
| 648 m_panelWidth = panelWidth; | |
| 649 | |
| 650 // Adjust for effective zoom. | |
| 651 if (!m_panel->layoutObject() || !m_panel->layoutObject()->style()) | |
| 652 return; | |
| 653 m_panelWidth = ceil(m_panelWidth / m_panel->layoutObject()->style()->effecti veZoom()); | |
| 654 | |
| 655 m_panelWidthChangedTimer.startOneShot(0, FROM_HERE); | |
| 656 } | |
| 657 | |
| 658 void MediaControls::panelWidthChangedTimerFired(Timer<MediaControls>*) | |
| 659 { | |
| 660 computeWhichControlsFit(); | |
| 661 } | |
| 662 | |
| 663 void MediaControls::computeWhichControlsFit() | |
| 664 { | |
| 665 // Hide all controls that don't fit, and show the ones that do. | |
| 666 // This might be better suited for a layout, but since JS media controls | |
| 667 // won't benefit from that anwyay, we just do it here like JS will. | |
| 668 // The order, in order of decreasing droppiness: | |
| 669 // Volume, time, seek bar, cast. | |
| 670 | |
| 671 if (!RuntimeEnabledFeatures::newMediaPlaybackUiEnabled()) | |
| 672 return; | |
| 673 | |
| 674 if (!m_panelWidth) | |
| 675 return; | |
| 676 | |
| 677 // Controls that we'll hide / show, in order of decreasing priority. | |
| 678 MediaControlElement* elements[] = { | |
| 679 m_playButton.get(), | |
| 680 m_toggleClosedCaptionsButton.get(), | |
| 681 m_fullScreenButton.get(), | |
| 682 m_timeline.get(), | |
| 683 m_currentTimeDisplay.get(), | |
| 684 m_volumeSlider.get(), | |
| 685 m_castButton.get(), | |
| 686 m_muteButton.get(), | |
| 687 m_durationDisplay.get(), | |
| 688 }; | |
| 689 | |
| 690 int usedWidth = 0; | |
| 691 bool droppedCastButton = false; | |
| 692 for (MediaControlElement* element : elements) { | |
| 693 if (!element) | |
| 694 continue; | |
| 695 | |
| 696 if (element->isWanted()) { | |
| 697 const int minimumWidth = element->minimumWidth(); | |
| 698 if (usedWidth + minimumWidth <= m_panelWidth) { | |
| 699 element->setDoesFit(true); | |
| 700 usedWidth += minimumWidth; | |
| 701 } else { | |
| 702 element->setDoesFit(false); | |
| 703 if (element == m_castButton.get()) | |
| 704 droppedCastButton = true; | |
| 705 } | |
| 706 } | |
| 707 } | |
| 708 | |
| 709 // Special case for cast: if we want a cast button but dropped it, then | |
| 710 // show the overlay cast button instead. | |
| 711 if (m_castButton->isWanted()) | |
| 712 m_overlayCastButton->setIsWanted(droppedCastButton); | |
| 713 } | |
| 714 | |
| 715 void MediaControls::setAllowHiddenVolumeControls(bool allow) | |
| 716 { | |
| 717 m_allowHiddenVolumeControls = allow; | |
| 718 // Clear the 'keep muted flag', for tests. | |
| 719 m_keepMuteButton = false; | |
| 720 // Update the controls visibility. | |
| 721 updateVolume(); | |
| 722 } | |
| 723 | |
| 724 void MediaControls::beginBatchUpdate() | |
| 725 { | |
| 726 ASSERT(m_batchDepth >= 0); | |
| 727 m_batchDepth++; | |
| 728 } | |
| 729 | |
| 730 void MediaControls::endBatchUpdate() | |
| 731 { | |
| 732 if (!(--m_batchDepth)) | |
| 733 computeWhichControlsFit(); | |
| 734 ASSERT(m_batchDepth >= 0); | |
| 735 } | |
| 736 | |
| 537 DEFINE_TRACE(MediaControls) | 737 DEFINE_TRACE(MediaControls) |
| 538 { | 738 { |
| 539 visitor->trace(m_mediaElement); | 739 visitor->trace(m_mediaElement); |
| 540 visitor->trace(m_panel); | 740 visitor->trace(m_panel); |
| 541 visitor->trace(m_overlayPlayButton); | 741 visitor->trace(m_overlayPlayButton); |
| 542 visitor->trace(m_overlayEnclosure); | 742 visitor->trace(m_overlayEnclosure); |
| 543 visitor->trace(m_playButton); | 743 visitor->trace(m_playButton); |
| 544 visitor->trace(m_currentTimeDisplay); | 744 visitor->trace(m_currentTimeDisplay); |
| 545 visitor->trace(m_timeline); | 745 visitor->trace(m_timeline); |
| 546 visitor->trace(m_muteButton); | 746 visitor->trace(m_muteButton); |
| 547 visitor->trace(m_volumeSlider); | 747 visitor->trace(m_volumeSlider); |
| 548 visitor->trace(m_toggleClosedCaptionsButton); | 748 visitor->trace(m_toggleClosedCaptionsButton); |
| 549 visitor->trace(m_fullScreenButton); | 749 visitor->trace(m_fullScreenButton); |
| 550 visitor->trace(m_durationDisplay); | 750 visitor->trace(m_durationDisplay); |
| 551 visitor->trace(m_enclosure); | 751 visitor->trace(m_enclosure); |
| 552 visitor->trace(m_castButton); | 752 visitor->trace(m_castButton); |
| 553 visitor->trace(m_overlayCastButton); | 753 visitor->trace(m_overlayCastButton); |
| 554 HTMLDivElement::trace(visitor); | 754 HTMLDivElement::trace(visitor); |
| 555 } | 755 } |
| 556 | 756 |
| 557 } | 757 } |
| OLD | NEW |