/* * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2011, 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #if ENABLE(VIDEO) #include "MediaControlsApple.h" #include "CSSValueKeywords.h" #include "ExceptionCodePlaceholder.h" #include "HTMLNames.h" #include "WheelEvent.h" namespace WebCore { MediaControlsApple::MediaControlsApple(Document& document) : MediaControls(document) , m_rewindButton(0) , m_returnToRealTimeButton(0) , m_statusDisplay(0) , m_timeRemainingDisplay(0) , m_timelineContainer(0) , m_seekBackButton(0) , m_seekForwardButton(0) , m_closedCaptionsTrackList(0) , m_closedCaptionsContainer(0) , m_volumeSliderMuteButton(0) , m_volumeSliderContainer(0) , m_fullScreenMinVolumeButton(0) , m_fullScreenVolumeSlider(0) , m_fullScreenMaxVolumeButton(0) { } PassRefPtr MediaControls::create(Document& document) { return MediaControlsApple::createControls(document); } PassRefPtr MediaControlsApple::createControls(Document& document) { if (!document.page()) return nullptr; RefPtr controls = adoptRef(new MediaControlsApple(document)); Ref panel = MediaControlPanelElement::create(document); ExceptionCode ec; Ref rewindButton = MediaControlRewindButtonElement::create(document); controls->m_rewindButton = rewindButton.ptr(); panel->appendChild(WTFMove(rewindButton), ec); if (ec) return nullptr; Ref playButton = MediaControlPlayButtonElement::create(document); controls->m_playButton = playButton.ptr(); panel->appendChild(WTFMove(playButton), ec); if (ec) return nullptr; Ref returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(document); controls->m_returnToRealTimeButton = returnToRealtimeButton.ptr(); panel->appendChild(WTFMove(returnToRealtimeButton), ec); if (ec) return nullptr; if (document.page()->theme().usesMediaControlStatusDisplay()) { Ref statusDisplay = MediaControlStatusDisplayElement::create(document); controls->m_statusDisplay = statusDisplay.ptr(); panel->appendChild(WTFMove(statusDisplay), ec); if (ec) return nullptr; } Ref timelineContainer = MediaControlTimelineContainerElement::create(document); Ref currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document); controls->m_currentTimeDisplay = currentTimeDisplay.ptr(); timelineContainer->appendChild(WTFMove(currentTimeDisplay), ec); if (ec) return nullptr; Ref timeline = MediaControlTimelineElement::create(document, controls.get()); controls->m_timeline = timeline.ptr(); timelineContainer->appendChild(WTFMove(timeline), ec); if (ec) return nullptr; Ref timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document); controls->m_timeRemainingDisplay = timeRemainingDisplay.ptr(); timelineContainer->appendChild(WTFMove(timeRemainingDisplay), ec); if (ec) return nullptr; controls->m_timelineContainer = timelineContainer.ptr(); panel->appendChild(WTFMove(timelineContainer), ec); if (ec) return nullptr; // FIXME: Only create when needed Ref seekBackButton = MediaControlSeekBackButtonElement::create(document); controls->m_seekBackButton = seekBackButton.ptr(); panel->appendChild(WTFMove(seekBackButton), ec); if (ec) return nullptr; // FIXME: Only create when needed Ref seekForwardButton = MediaControlSeekForwardButtonElement::create(document); controls->m_seekForwardButton = seekForwardButton.ptr(); panel->appendChild(WTFMove(seekForwardButton), ec); if (ec) return nullptr; if (document.page()->theme().supportsClosedCaptioning()) { Ref closedCaptionsContainer = MediaControlClosedCaptionsContainerElement::create(document); Ref closedCaptionsTrackList = MediaControlClosedCaptionsTrackListElement::create(document, controls.get()); controls->m_closedCaptionsTrackList = closedCaptionsTrackList.ptr(); closedCaptionsContainer->appendChild(WTFMove(closedCaptionsTrackList), ec); if (ec) return nullptr; Ref toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get()); controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.ptr(); panel->appendChild(WTFMove(toggleClosedCaptionsButton), ec); if (ec) return nullptr; controls->m_closedCaptionsContainer = closedCaptionsContainer.ptr(); controls->appendChild(WTFMove(closedCaptionsContainer), ec); if (ec) return nullptr; } // FIXME: Only create when needed Ref fullScreenButton = MediaControlFullscreenButtonElement::create(document); controls->m_fullScreenButton = fullScreenButton.ptr(); panel->appendChild(WTFMove(fullScreenButton), ec); // The mute button and the slider element should be in the same div. Ref panelVolumeControlContainer = HTMLDivElement::create(document); if (document.page()->theme().usesMediaControlVolumeSlider()) { Ref volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document); Ref slider = MediaControlPanelVolumeSliderElement::create(document); controls->m_volumeSlider = slider.ptr(); volumeSliderContainer->appendChild(WTFMove(slider), ec); if (ec) return nullptr; // This is a duplicate mute button, which is visible in some ports at the bottom of the volume bar. // It's important only when the volume bar is displayed below the controls. Ref volumeSliderMuteButton = MediaControlVolumeSliderMuteButtonElement::create(document); controls->m_volumeSliderMuteButton = volumeSliderMuteButton.ptr(); volumeSliderContainer->appendChild(WTFMove(volumeSliderMuteButton), ec); if (ec) return nullptr; controls->m_volumeSliderContainer = volumeSliderContainer.ptr(); panelVolumeControlContainer->appendChild(WTFMove(volumeSliderContainer), ec); if (ec) return nullptr; } Ref panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.get()); controls->m_panelMuteButton = panelMuteButton.ptr(); panelVolumeControlContainer->appendChild(WTFMove(panelMuteButton), ec); if (ec) return nullptr; panel->appendChild(WTFMove(panelVolumeControlContainer), ec); if (ec) return nullptr; // FIXME: Only create when needed Ref fullScreenMinVolumeButton = MediaControlFullscreenVolumeMinButtonElement::create(document); controls->m_fullScreenMinVolumeButton = fullScreenMinVolumeButton.ptr(); panel->appendChild(WTFMove(fullScreenMinVolumeButton), ec); if (ec) return nullptr; Ref fullScreenVolumeSlider = MediaControlFullscreenVolumeSliderElement::create(document); controls->m_fullScreenVolumeSlider = fullScreenVolumeSlider.ptr(); panel->appendChild(WTFMove(fullScreenVolumeSlider), ec); if (ec) return nullptr; Ref fullScreenMaxVolumeButton = MediaControlFullscreenVolumeMaxButtonElement::create(document); controls->m_fullScreenMaxVolumeButton = fullScreenMaxVolumeButton.ptr(); panel->appendChild(WTFMove(fullScreenMaxVolumeButton), ec); if (ec) return nullptr; controls->m_panel = panel.ptr(); controls->appendChild(WTFMove(panel), ec); if (ec) return nullptr; return controls.release(); } void MediaControlsApple::setMediaController(MediaControllerInterface* controller) { if (m_mediaController == controller) return; MediaControls::setMediaController(controller); if (m_rewindButton) m_rewindButton->setMediaController(controller); if (m_returnToRealTimeButton) m_returnToRealTimeButton->setMediaController(controller); if (m_statusDisplay) m_statusDisplay->setMediaController(controller); if (m_timeRemainingDisplay) m_timeRemainingDisplay->setMediaController(controller); if (m_timelineContainer) m_timelineContainer->setMediaController(controller); if (m_seekBackButton) m_seekBackButton->setMediaController(controller); if (m_seekForwardButton) m_seekForwardButton->setMediaController(controller); if (m_volumeSliderMuteButton) m_volumeSliderMuteButton->setMediaController(controller); if (m_volumeSliderContainer) m_volumeSliderContainer->setMediaController(controller); if (m_fullScreenMinVolumeButton) m_fullScreenMinVolumeButton->setMediaController(controller); if (m_fullScreenVolumeSlider) m_fullScreenVolumeSlider->setMediaController(controller); if (m_fullScreenMaxVolumeButton) m_fullScreenMaxVolumeButton->setMediaController(controller); if (m_closedCaptionsTrackList) m_closedCaptionsTrackList->setMediaController(controller); if (m_closedCaptionsContainer) m_closedCaptionsContainer->setMediaController(controller); } void MediaControlsApple::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing()) { hideClosedCaptionTrackList(); event->setDefaultHandled(); } } MediaControls::defaultEventHandler(event); } void MediaControlsApple::hide() { MediaControls::hide(); m_volumeSliderContainer->hide(); if (m_closedCaptionsContainer) hideClosedCaptionTrackList(); } void MediaControlsApple::makeTransparent() { MediaControls::makeTransparent(); m_volumeSliderContainer->hide(); if (m_closedCaptionsContainer) hideClosedCaptionTrackList(); } void MediaControlsApple::changedClosedCaptionsVisibility() { MediaControls::changedClosedCaptionsVisibility(); if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing()) hideClosedCaptionTrackList(); } void MediaControlsApple::reset() { Page* page = document().page(); if (!page) return; updateStatusDisplay(); if (m_mediaController->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard)) m_fullScreenButton->show(); else m_fullScreenButton->hide(); double duration = m_mediaController->duration(); if (std::isfinite(duration) || page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) { m_timeline->setDuration(duration); m_timelineContainer->show(); m_timeline->setPosition(m_mediaController->currentTime()); updateCurrentTimeDisplay(); } else m_timelineContainer->hide(); if (m_mediaController->hasAudio() || page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) m_panelMuteButton->show(); else m_panelMuteButton->hide(); if (m_volumeSlider) setSliderVolume(); if (m_toggleClosedCaptionsButton) { if (m_mediaController->hasClosedCaptions()) m_toggleClosedCaptionsButton->show(); else m_toggleClosedCaptionsButton->hide(); } if (m_playButton) m_playButton->updateDisplayType(); #if ENABLE(FULLSCREEN_API) if (m_fullScreenVolumeSlider) setFullscreenSliderVolume(); if (m_isFullscreen) { if (m_mediaController->isLiveStream()) { m_seekBackButton->hide(); m_seekForwardButton->hide(); m_rewindButton->show(); m_returnToRealTimeButton->show(); } else { m_seekBackButton->show(); m_seekForwardButton->show(); m_rewindButton->hide(); m_returnToRealTimeButton->hide(); } } else #endif if (!m_mediaController->isLiveStream()) { m_returnToRealTimeButton->hide(); m_rewindButton->show(); } else { m_returnToRealTimeButton->show(); m_rewindButton->hide(); } makeOpaque(); } void MediaControlsApple::updateCurrentTimeDisplay() { double now = m_mediaController->currentTime(); double duration = m_mediaController->duration(); Page* page = document().page(); if (!page) return; // Allow the theme to format the time. m_currentTimeDisplay->setInnerText(page->theme().formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION); m_currentTimeDisplay->setCurrentValue(now); m_timeRemainingDisplay->setInnerText(page->theme().formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); m_timeRemainingDisplay->setCurrentValue(now - duration); } void MediaControlsApple::reportedError() { Page* page = document().page(); if (!page) return; if (!page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) m_timelineContainer->hide(); if (!page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) m_panelMuteButton->hide(); m_fullScreenButton->hide(); if (m_volumeSliderContainer) m_volumeSliderContainer->hide(); if (m_toggleClosedCaptionsButton && !page->theme().hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart)) m_toggleClosedCaptionsButton->hide(); if (m_closedCaptionsContainer) hideClosedCaptionTrackList(); } void MediaControlsApple::updateStatusDisplay() { if (m_statusDisplay) m_statusDisplay->update(); } void MediaControlsApple::loadedMetadata() { if (m_statusDisplay && !m_mediaController->isLiveStream()) m_statusDisplay->hide(); MediaControls::loadedMetadata(); } void MediaControlsApple::changedMute() { MediaControls::changedMute(); if (m_volumeSliderMuteButton) m_volumeSliderMuteButton->changedMute(); } void MediaControlsApple::changedVolume() { MediaControls::changedVolume(); if (m_fullScreenVolumeSlider) setFullscreenSliderVolume(); } void MediaControlsApple::enteredFullscreen() { MediaControls::enteredFullscreen(); m_panel->setCanBeDragged(true); if (m_mediaController->isLiveStream()) { m_seekBackButton->hide(); m_seekForwardButton->hide(); m_rewindButton->show(); m_returnToRealTimeButton->show(); } else { m_seekBackButton->show(); m_seekForwardButton->show(); m_rewindButton->hide(); m_returnToRealTimeButton->hide(); } } void MediaControlsApple::exitedFullscreen() { m_rewindButton->show(); m_seekBackButton->show(); m_seekForwardButton->show(); m_returnToRealTimeButton->show(); m_panel->setCanBeDragged(false); // We will keep using the panel, but we want it to go back to the standard position. // This will matter right away because we use the panel even when not fullscreen. // And if we reenter fullscreen we also want the panel in the standard position. m_panel->resetPosition(); MediaControls::exitedFullscreen(); } void MediaControlsApple::showVolumeSlider() { if (!m_mediaController->hasAudio()) return; if (m_volumeSliderContainer) m_volumeSliderContainer->show(); } void MediaControlsApple::toggleClosedCaptionTrackList() { if (!m_mediaController->hasClosedCaptions()) return; if (m_closedCaptionsContainer) { if (m_closedCaptionsContainer->isShowing()) hideClosedCaptionTrackList(); else { if (m_closedCaptionsTrackList) m_closedCaptionsTrackList->updateDisplay(); showClosedCaptionTrackList(); } } } void MediaControlsApple::showClosedCaptionTrackList() { if (!m_closedCaptionsContainer || m_closedCaptionsContainer->isShowing()) return; m_closedCaptionsContainer->show(); // Ensure the controls panel does not receive any events while the captions // track list is visible as all events now need to be captured by the // track list. m_panel->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone); RefPtr listener = eventListener(); m_closedCaptionsContainer->addEventListener(eventNames().wheelEvent, listener.copyRef(), true); // Track click events in the capture phase at two levels, first at the document level // such that a click outside of the