/* * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. * Copyright (C) 2011 Google Inc. All rights reserved. * Copyright (C) 2012 Research In Motion Limited. 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 COMPUTER, 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 COMPUTER, 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 "MediaControlsBlackBerry.h" #include "Chrome.h" #include "DOMTokenList.h" #include "ExceptionCodePlaceholder.h" #include "Frame.h" #include "HTMLMediaElement.h" #include "HTMLNames.h" #include "MediaControlElements.h" #include "MouseEvent.h" #include "Page.h" #include "RenderDeprecatedFlexibleBox.h" #include "RenderSlider.h" #include "RenderTheme.h" #include "Settings.h" #include "Text.h" #if ENABLE(VIDEO_TRACK) #include "TextTrackCue.h" #endif using namespace std; namespace WebCore { using namespace HTMLNames; static const double timeWithoutMouseMovementBeforeHidingControls = 3; inline MediaControlButtonGroupContainerElement::MediaControlButtonGroupContainerElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlButtonGroupContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlButtonGroupContainerElement(document)); return element.release(); } const AtomicString& MediaControlButtonGroupContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-button-group-container", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlTimeDisplayContainerElement::MediaControlTimeDisplayContainerElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlTimeDisplayContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlTimeDisplayContainerElement(document)); return element.release(); } const AtomicString& MediaControlTimeDisplayContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-display-container", AtomicString::ConstructFromLiteral)); return id; } MediaControlEmbeddedPanelElement::MediaControlEmbeddedPanelElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) , m_canBeDragged(false) , m_isBeingDragged(false) , m_isDisplayed(false) , m_opaque(true) , m_transitionTimer(this, &MediaControlEmbeddedPanelElement::transitionTimerFired) { } PassRefPtr MediaControlEmbeddedPanelElement::create(Document* document) { return adoptRef(new MediaControlEmbeddedPanelElement(document)); } const AtomicString& MediaControlEmbeddedPanelElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-embedded-panel", AtomicString::ConstructFromLiteral)); return id; } void MediaControlEmbeddedPanelElement::startDrag(const LayoutPoint& eventLocation) { if (!m_canBeDragged) return; if (m_isBeingDragged) return; RenderObject* renderer = this->renderer(); if (!renderer || !renderer->isBox()) return; Frame* frame = document()->frame(); if (!frame) return; m_lastDragEventLocation = eventLocation; frame->eventHandler()->setCapturingMouseEventsNode(this); m_isBeingDragged = true; } void MediaControlEmbeddedPanelElement::continueDrag(const LayoutPoint& eventLocation) { if (!m_isBeingDragged) return; LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation; m_cumulativeDragOffset.move(distanceDragged); m_lastDragEventLocation = eventLocation; setPosition(m_cumulativeDragOffset); } void MediaControlEmbeddedPanelElement::endDrag() { if (!m_isBeingDragged) return; m_isBeingDragged = false; Frame* frame = document()->frame(); if (!frame) return; frame->eventHandler()->setCapturingMouseEventsNode(0); } void MediaControlEmbeddedPanelElement::startTimer() { stopTimer(); // The timer is required to set the property display:'none' on the panel, // such that captions are correctly displayed at the bottom of the video // at the end of the fadeout transition. double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; m_transitionTimer.startOneShot(duration); } void MediaControlEmbeddedPanelElement::stopTimer() { if (m_transitionTimer.isActive()) m_transitionTimer.stop(); } void MediaControlEmbeddedPanelElement::transitionTimerFired(Timer*) { if (!m_opaque) hide(); stopTimer(); } void MediaControlEmbeddedPanelElement::setPosition(const LayoutPoint& position) { double left = position.x(); double top = position.y(); // Set the left and top to control the panel's position; this depends on it being absolute positioned. // Set the margin to zero since the position passed in will already include the effect of the margin. setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX); setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX); classList()->add("dragged", IGNORE_EXCEPTION); } void MediaControlEmbeddedPanelElement::resetPosition() { removeInlineStyleProperty(CSSPropertyLeft); removeInlineStyleProperty(CSSPropertyTop); removeInlineStyleProperty(CSSPropertyMarginLeft); removeInlineStyleProperty(CSSPropertyMarginTop); classList()->remove("dragged", IGNORE_EXCEPTION); m_cumulativeDragOffset.setX(0); m_cumulativeDragOffset.setY(0); } void MediaControlEmbeddedPanelElement::makeOpaque() { if (m_opaque) return; double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0; setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity); setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S); setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER); m_opaque = true; if (m_isDisplayed) show(); } void MediaControlEmbeddedPanelElement::makeTransparent() { if (!m_opaque) return; double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity); setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S); setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER); m_opaque = false; startTimer(); } void MediaControlEmbeddedPanelElement::defaultEventHandler(Event* event) { MediaControlDivElement::defaultEventHandler(event); if (event->isMouseEvent()) { LayoutPoint location = static_cast(event)->absoluteLocation(); if (event->type() == eventNames().mousedownEvent && event->target() == this) { startDrag(location); event->setDefaultHandled(); } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged) continueDrag(location); else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) { continueDrag(location); endDrag(); event->setDefaultHandled(); } } } void MediaControlEmbeddedPanelElement::setCanBeDragged(bool canBeDragged) { if (m_canBeDragged == canBeDragged) return; m_canBeDragged = canBeDragged; if (!canBeDragged) endDrag(); } void MediaControlEmbeddedPanelElement::setIsDisplayed(bool isDisplayed) { m_isDisplayed = isDisplayed; } inline MediaControlFullscreenTimeDisplayContainerElement::MediaControlFullscreenTimeDisplayContainerElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlFullscreenTimeDisplayContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlFullscreenTimeDisplayContainerElement(document)); return element.release(); } const AtomicString& MediaControlFullscreenTimeDisplayContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-display-container", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlFullscreenButtonContainerElement::MediaControlFullscreenButtonContainerElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlFullscreenButtonContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlFullscreenButtonContainerElement(document)); return element.release(); } const AtomicString& MediaControlFullscreenButtonContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-container", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlFullscreenButtonDividerElement::MediaControlFullscreenButtonDividerElement(Document* document) : MediaControlDivElement(document, MediaRewindButton) { } PassRefPtr MediaControlFullscreenButtonDividerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlFullscreenButtonDividerElement(document)); return element.release(); } const AtomicString& MediaControlFullscreenButtonDividerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-divider", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlPlayButtonContainerElement::MediaControlPlayButtonContainerElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlPlayButtonContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlPlayButtonContainerElement(document)); return element.release(); } const AtomicString& MediaControlPlayButtonContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button-container", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlPlaceholderElement::MediaControlPlaceholderElement(Document* document) : MediaControlDivElement(document, MediaControlsPanel) { } PassRefPtr MediaControlPlaceholderElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlPlaceholderElement(document)); return element.release(); } const AtomicString& MediaControlPlaceholderElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-placeholder", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlFullscreenPlayButtonElement::MediaControlFullscreenPlayButtonElement(Document* document) : MediaControlInputElement(document, MediaPlayButton) { } PassRefPtr MediaControlFullscreenPlayButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlFullscreenPlayButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } void MediaControlFullscreenPlayButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { if (mediaController()->canPlay()) mediaController()->play(); else mediaController()->pause(); updateDisplayType(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } void MediaControlFullscreenPlayButtonElement::updateDisplayType() { setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton); } const AtomicString& MediaControlFullscreenPlayButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-play-button", AtomicString::ConstructFromLiteral)); return id; } inline MediaControlFullscreenFullscreenButtonElement::MediaControlFullscreenFullscreenButtonElement(Document* document) : MediaControlInputElement(document, MediaExitFullscreenButton) { } PassRefPtr MediaControlFullscreenFullscreenButtonElement::create(Document* document) { RefPtr button = adoptRef(new MediaControlFullscreenFullscreenButtonElement(document)); button->ensureUserAgentShadowRoot(); button->setType("button"); button->hide(); return button.release(); } void MediaControlFullscreenFullscreenButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().clickEvent) { #if ENABLE(FULLSCREEN_API) // Only use the new full screen API if the fullScreenEnabled setting has // been explicitly enabled. Otherwise, use the old fullscreen API. This // allows apps which embed a WebView to retain the existing full screen // video implementation without requiring them to implement their own full // screen behavior. if (document()->settings() && document()->settings()->fullScreenEnabled()) { if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this)) document()->webkitCancelFullScreen(); else document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement); } else #endif mediaController()->enterFullscreen(); event->setDefaultHandled(); } HTMLInputElement::defaultEventHandler(event); } const AtomicString& MediaControlFullscreenFullscreenButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-fullscreen-button", AtomicString::ConstructFromLiteral)); return id; } void MediaControlFullscreenFullscreenButtonElement::setIsFullscreen(bool) { setDisplayType(MediaExitFullscreenButton); } inline MediaControlFullscreenTimelineContainerElement::MediaControlFullscreenTimelineContainerElement(Document* document) : MediaControlDivElement(document, MediaTimelineContainer) { } PassRefPtr MediaControlFullscreenTimelineContainerElement::create(Document* document) { RefPtr element = adoptRef(new MediaControlFullscreenTimelineContainerElement(document)); element->hide(); return element.release(); } const AtomicString& MediaControlFullscreenTimelineContainerElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline-container", AtomicString::ConstructFromLiteral)); return id; } MediaControlFullscreenTimelineElement::MediaControlFullscreenTimelineElement(Document* document, MediaControls* controls) : MediaControlInputElement(document, MediaSlider) , m_controls(controls) { } PassRefPtr MediaControlFullscreenTimelineElement::create(Document* document, MediaControls* controls) { ASSERT(controls); RefPtr timeline = adoptRef(new MediaControlFullscreenTimelineElement(document, controls)); timeline->ensureUserAgentShadowRoot(); timeline->setType("range"); timeline->setAttribute(precisionAttr, "double"); return timeline.release(); } void MediaControlFullscreenTimelineElement::defaultEventHandler(Event* event) { // Left button is 0. Rejects mouse events not from left button. if (event->isMouseEvent() && static_cast(event)->button()) return; if (!attached()) return; if (event->type() == eventNames().mousedownEvent) mediaController()->beginScrubbing(); if (event->type() == eventNames().mouseupEvent) mediaController()->endScrubbing(); MediaControlInputElement::defaultEventHandler(event); if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) return; double time = value().toDouble(); if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) mediaController()->setCurrentTime(time, IGNORE_EXCEPTION); RenderSlider* slider = toRenderSlider(renderer()); if (slider && slider->inDragMode()) m_controls->updateCurrentTimeDisplay(); } bool MediaControlFullscreenTimelineElement::willRespondToMouseClickEvents() { if (!attached()) return false; return true; } void MediaControlFullscreenTimelineElement::setPosition(double currentTime) { setValue(String::number(currentTime)); } void MediaControlFullscreenTimelineElement::setDuration(double duration) { setAttribute(maxAttr, String::number(std::isfinite(duration) ? duration : 0)); } const AtomicString& MediaControlFullscreenTimelineElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline", AtomicString::ConstructFromLiteral)); return id; } PassRefPtr MediaControlFullscreenTimeRemainingDisplayElement::create(Document* document) { return adoptRef(new MediaControlFullscreenTimeRemainingDisplayElement(document)); } MediaControlFullscreenTimeRemainingDisplayElement::MediaControlFullscreenTimeRemainingDisplayElement(Document* document) : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay) { } const AtomicString& MediaControlFullscreenTimeRemainingDisplayElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-remaining-display", AtomicString::ConstructFromLiteral)); return id; } PassRefPtr MediaControlFullscreenCurrentTimeDisplayElement::create(Document* document) { return adoptRef(new MediaControlFullscreenCurrentTimeDisplayElement(document)); } MediaControlFullscreenCurrentTimeDisplayElement::MediaControlFullscreenCurrentTimeDisplayElement(Document* document) : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay) { } const AtomicString& MediaControlFullscreenCurrentTimeDisplayElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-current-time-display", AtomicString::ConstructFromLiteral)); return id; } MediaControlAudioMuteButtonElement::MediaControlAudioMuteButtonElement(Document* document, MediaControls* controls) : MediaControlMuteButtonElement(document, MediaMuteButton) , m_controls(controls) { } PassRefPtr MediaControlAudioMuteButtonElement::create(Document* document, MediaControls* controls) { ASSERT(controls); RefPtr button = adoptRef(new MediaControlAudioMuteButtonElement(document, controls)); button->ensureUserAgentShadowRoot(); button->setType("button"); return button.release(); } void MediaControlAudioMuteButtonElement::defaultEventHandler(Event* event) { if (event->type() == eventNames().mousedownEvent) { // We do not mute when the media player volume/mute control is touched. // Instead we show/hide the volume slider. static_cast(m_controls)->toggleVolumeSlider(); event->setDefaultHandled(); return; } if (event->type() == eventNames().mouseoverEvent) m_controls->showVolumeSlider(); MediaControlMuteButtonElement::defaultEventHandler(event); } const AtomicString& MediaControlAudioMuteButtonElement::shadowPseudoId() const { DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-audio-mute-button", AtomicString::ConstructFromLiteral)); return id; } MediaControlsBlackBerry::MediaControlsBlackBerry(Document* document) : MediaControls(document) , m_buttonContainer(0) , m_timeDisplayContainer(0) , m_fullscreenTimeDisplayContainer(0) , m_fullscreenPlayButton(0) , m_fullscreenCurrentTimeDisplay(0) , m_fullscreenTimeline(0) , m_timeRemainingDisplay(0) , m_fullscreenTimeRemainingDisplay(0) , m_timelineContainer(0) , m_fullscreenTimelineContainer(0) , m_fullScreenDivider(0) , m_fullscreenFullScreenButton(0) , m_muteButton(0) , m_volumeSliderContainer(0) , m_embeddedPanel(0) , m_fullScreenButtonContainer(0) , m_playButtonContainer(0) , m_placeholder(0) { } PassRefPtr MediaControls::create(Document* document) { return MediaControlsBlackBerry::createControls(document); } PassRefPtr MediaControlsBlackBerry::createControls(Document* document) { if (!document->page()) return 0; RefPtr controls = adoptRef(new MediaControlsBlackBerry(document)); RefPtr panel = MediaControlPanelElement::create(document); RefPtr embedPanel = MediaControlEmbeddedPanelElement::create(document); ExceptionCode ec; RefPtr playButton = MediaControlPlayButtonElement::create(document); controls->m_playButton = playButton.get(); embedPanel->appendChild(playButton.release(), ec, AttachLazily); if (ec) return 0; RefPtr timelineContainer = MediaControlTimelineContainerElement::create(document); RefPtr timeline = MediaControlTimelineElement::create(document, controls.get()); controls->m_timeline = timeline.get(); timelineContainer->appendChild(timeline.release(), ec, AttachLazily); if (ec) return 0; RefPtr timeDisplayContainer = MediaControlTimeDisplayContainerElement::create(document); RefPtr currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document); controls->m_currentTimeDisplay = currentTimeDisplay.get(); timeDisplayContainer->appendChild(currentTimeDisplay.release(), ec, AttachLazily); if (ec) return 0; RefPtr timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document); controls->m_timeRemainingDisplay = timeRemainingDisplay.get(); timeDisplayContainer->appendChild(timeRemainingDisplay.release(), ec, AttachLazily); if (ec) return 0; controls->m_timeDisplayContainer = timeDisplayContainer.get(); timelineContainer->appendChild(timeDisplayContainer.release(), ec, AttachLazily); if (ec) return 0; controls->m_timelineContainer = timelineContainer.get(); embedPanel->appendChild(timelineContainer.release(), ec, AttachLazily); if (ec) return 0; RefPtr fullScreenButton = MediaControlFullscreenButtonElement::create(document); controls->m_fullScreenButton = fullScreenButton.get(); embedPanel->appendChild(fullScreenButton.release(), ec, AttachLazily); if (ec) return 0; if (document->page()->theme()->usesMediaControlVolumeSlider()) { // The mute button and the slider element should be in the same div. RefPtr volumeControlContainer = HTMLDivElement::create(document); RefPtr volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document); RefPtr slider = MediaControlPanelVolumeSliderElement::create(document); controls->m_volumeSlider = slider.get(); volumeSliderContainer->appendChild(slider.release(), ec, AttachLazily); if (ec) return 0; controls->m_volumeSliderContainer = volumeSliderContainer.get(); volumeControlContainer->appendChild(volumeSliderContainer.release(), ec, AttachLazily); if (ec) return 0; RefPtr muteButton = MediaControlAudioMuteButtonElement::create(document, controls.get()); controls->m_muteButton = muteButton.get(); volumeControlContainer->appendChild(muteButton.release(), ec, AttachLazily); if (ec) return 0; embedPanel->appendChild(volumeControlContainer.release(), ec, AttachLazily); if (ec) return 0; } RefPtr fullscreenTimelineContainer = MediaControlFullscreenTimelineContainerElement::create(document); RefPtr fullscreenTimeline = MediaControlFullscreenTimelineElement::create(document, controls.get()); controls->m_fullscreenTimeline = fullscreenTimeline.get(); fullscreenTimelineContainer->appendChild(fullscreenTimeline.release(), ec, AttachLazily); if (ec) return 0; RefPtr fullscreenTimeDisplayContainer = MediaControlFullscreenTimeDisplayContainerElement::create(document); RefPtr fullscreenCurrentTimeDisplay = MediaControlFullscreenCurrentTimeDisplayElement::create(document); controls->m_fullscreenCurrentTimeDisplay = fullscreenCurrentTimeDisplay.get(); fullscreenTimeDisplayContainer->appendChild(fullscreenCurrentTimeDisplay.release(), ec, AttachLazily); if (ec) return 0; RefPtr fullscreenTimeRemainingDisplay = MediaControlFullscreenTimeRemainingDisplayElement::create(document); controls->m_fullscreenTimeRemainingDisplay = fullscreenTimeRemainingDisplay.get(); fullscreenTimeDisplayContainer->appendChild(fullscreenTimeRemainingDisplay.release(), ec, AttachLazily); if (ec) return 0; controls->m_fullscreenTimeDisplayContainer = fullscreenTimeDisplayContainer.get(); fullscreenTimelineContainer->appendChild(fullscreenTimeDisplayContainer.release(), ec, AttachLazily); if (ec) return 0; controls->m_fullscreenTimelineContainer = fullscreenTimelineContainer.get(); panel->appendChild(fullscreenTimelineContainer.release(), ec, AttachLazily); if (ec) return 0; RefPtr buttonGroupContainer = MediaControlButtonGroupContainerElement::create(document); // FIXME: Only create when needed RefPtr fullScreenButtonContainer = MediaControlFullscreenButtonContainerElement::create(document); controls->m_fullScreenButtonContainer = fullScreenButtonContainer.get(); RefPtr fullscreenFullScreenButton = MediaControlFullscreenFullscreenButtonElement::create(document); controls->m_fullscreenFullScreenButton = fullscreenFullScreenButton.get(); fullScreenButtonContainer->appendChild(fullscreenFullScreenButton.release(), ec, AttachLazily); if (ec) return 0; RefPtr fullScreenDivider = MediaControlFullscreenButtonDividerElement::create(document); controls->m_fullScreenDivider = fullScreenDivider.get(); fullScreenButtonContainer->appendChild(fullScreenDivider.release(), ec, AttachLazily); if (ec) return 0; buttonGroupContainer->appendChild(fullScreenButtonContainer.release(), ec, AttachLazily); if (ec) return 0; RefPtr playButtonContainer = MediaControlPlayButtonContainerElement::create(document); controls->m_playButtonContainer = playButtonContainer.get(); RefPtr fullscreenPlayButton = MediaControlFullscreenPlayButtonElement::create(document); controls->m_fullscreenPlayButton = fullscreenPlayButton.get(); playButtonContainer->appendChild(fullscreenPlayButton.release(), ec, AttachLazily); if (ec) return 0; buttonGroupContainer->appendChild(playButtonContainer.release(), ec, AttachLazily); if (ec) return 0; RefPtr placeholder = MediaControlPlaceholderElement::create(document); controls->m_placeholder = placeholder.get(); buttonGroupContainer->appendChild(placeholder.release(), ec, AttachLazily); if (ec) return 0; controls->m_buttonContainer = buttonGroupContainer.get(); panel->appendChild(buttonGroupContainer.release(), ec, AttachLazily); if (ec) return 0; if (document->page()->theme()->supportsClosedCaptioning()) { RefPtr toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get()); controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); panel->appendChild(toggleClosedCaptionsButton.release(), ec, AttachLazily); if (ec) return 0; } controls->m_panel = panel.get(); controls->appendChild(panel.release(), ec, AttachLazily); if (ec) return 0; controls->m_embeddedPanel = embedPanel.get(); controls->appendChild(embedPanel.release(), ec, AttachLazily); if (ec) return 0; return controls.release(); } void MediaControlsBlackBerry::setMediaController(MediaControllerInterface* controller) { if (m_mediaController == controller) return; MediaControls::setMediaController(controller); if (m_buttonContainer) m_buttonContainer->setMediaController(controller); if (m_timeDisplayContainer) m_timeDisplayContainer->setMediaController(controller); if (m_fullscreenTimeDisplayContainer) m_fullscreenTimeDisplayContainer->setMediaController(controller); if (m_fullscreenPlayButton) m_fullscreenPlayButton->setMediaController(controller); if (m_fullscreenCurrentTimeDisplay) m_fullscreenCurrentTimeDisplay->setMediaController(controller); if (m_fullscreenTimeline) m_fullscreenTimeline->setMediaController(controller); if (m_timeRemainingDisplay) m_timeRemainingDisplay->setMediaController(controller); if (m_fullscreenTimeRemainingDisplay) m_fullscreenTimeRemainingDisplay->setMediaController(controller); if (m_timelineContainer) m_timelineContainer->setMediaController(controller); if (m_fullscreenTimelineContainer) m_fullscreenTimelineContainer->setMediaController(controller); if (m_fullscreenFullScreenButton) m_fullscreenFullScreenButton->setMediaController(controller); if (m_muteButton) m_muteButton->setMediaController(controller); if (m_volumeSliderContainer) m_volumeSliderContainer->setMediaController(controller); if (m_embeddedPanel) m_embeddedPanel->setMediaController(controller); reset(); } void MediaControlsBlackBerry::show() { if (m_isFullscreen) { m_panel->setIsDisplayed(true); m_panel->show(); } else { m_embeddedPanel->setIsDisplayed(true); m_embeddedPanel->show(); } } void MediaControlsBlackBerry::hide() { if (m_isFullscreen) { m_panel->setIsDisplayed(false); m_panel->hide(); } else { m_embeddedPanel->setIsDisplayed(false); m_embeddedPanel->hide(); m_volumeSliderContainer->hide(); } } void MediaControlsBlackBerry::makeOpaque() { if (m_isFullscreen) m_panel->makeOpaque(); else m_embeddedPanel->makeOpaque(); } void MediaControlsBlackBerry::makeTransparent() { if (m_isFullscreen) m_panel->makeTransparent(); else { m_embeddedPanel->makeTransparent(); m_volumeSliderContainer->hide(); } } void MediaControlsBlackBerry::reset() { Page* page = document()->page(); if (!page) return; updateStatusDisplay(); if (m_fullScreenButton) { if (m_mediaController->supportsFullscreen()) m_fullScreenButton->show(); else m_fullScreenButton->hide(); } if (m_fullscreenFullScreenButton) { if (m_mediaController->supportsFullscreen()) m_fullscreenFullScreenButton->show(); else m_fullscreenFullScreenButton->hide(); } double duration = m_mediaController->duration(); if (std::isfinite(duration) || page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) { double now = m_mediaController->currentTime(); m_timeline->setDuration(duration); m_fullscreenTimeline->setDuration(duration); m_timelineContainer->show(); m_fullscreenTimelineContainer->show(); m_timeline->setPosition(now); m_fullscreenTimeline->setPosition(now); updateCurrentTimeDisplay(); } else { m_timelineContainer->hide(); m_fullscreenTimelineContainer->hide(); } if (m_mediaController->hasAudio() || page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) m_muteButton->show(); else m_muteButton->hide(); if (m_volumeSlider) m_volumeSlider->setVolume(m_mediaController->volume()); if (m_toggleClosedCaptionsButton) { if (m_mediaController->hasClosedCaptions()) m_toggleClosedCaptionsButton->show(); else m_toggleClosedCaptionsButton->hide(); } if (m_playButton) m_playButton->updateDisplayType(); if (m_fullscreenPlayButton) m_fullscreenPlayButton->updateDisplayType(); makeOpaque(); } void MediaControlsBlackBerry::bufferingProgressed() { // We only need to update buffering progress when paused, during normal // playback playbackProgressed() will take care of it. if (m_mediaController->paused()) { double now = m_mediaController->currentTime(); m_timeline->setPosition(now); m_fullscreenTimeline->setPosition(now); } } void MediaControlsBlackBerry::playbackStarted() { double now = m_mediaController->currentTime(); m_playButton->updateDisplayType(); m_fullscreenPlayButton->updateDisplayType(); m_timeline->setPosition(now); m_fullscreenTimeline->setPosition(now); updateCurrentTimeDisplay(); if (m_isFullscreen) startHideFullscreenControlsTimer(); } void MediaControlsBlackBerry::playbackProgressed() { double now = m_mediaController->currentTime(); m_timeline->setPosition(now); m_fullscreenTimeline->setPosition(now); updateCurrentTimeDisplay(); if (!m_isMouseOverControls && m_mediaController->hasVideo()) makeTransparent(); } void MediaControlsBlackBerry::playbackStopped() { double now = m_mediaController->currentTime(); m_playButton->updateDisplayType(); m_fullscreenPlayButton->updateDisplayType(); m_timeline->setPosition(now); m_fullscreenTimeline->setPosition(now); updateCurrentTimeDisplay(); makeOpaque(); stopHideFullscreenControlsTimer(); } void MediaControlsBlackBerry::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_fullscreenCurrentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION); m_fullscreenCurrentTimeDisplay->setCurrentValue(now); m_timeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); m_timeRemainingDisplay->setCurrentValue(now - duration); m_fullscreenTimeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); m_fullscreenTimeRemainingDisplay->setCurrentValue(now - duration); } void MediaControlsBlackBerry::reportedError() { Page* page = document()->page(); if (!page) return; if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) { m_timelineContainer->hide(); m_fullscreenTimelineContainer->hide(); } if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) m_muteButton->hide(); if (m_fullScreenButton) m_fullScreenButton->hide(); if (m_fullScreenDivider) m_fullScreenDivider->hide(); if (m_fullscreenFullScreenButton) m_fullscreenFullScreenButton->hide(); if (m_volumeSliderContainer) m_volumeSliderContainer->hide(); if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart)) m_toggleClosedCaptionsButton->hide(); } void MediaControlsBlackBerry::changedMute() { m_muteButton->changedMute(); } void MediaControlsBlackBerry::enteredFullscreen() { MediaControls::enteredFullscreen(); m_panel->setCanBeDragged(true); m_embeddedPanel->setCanBeDragged(true); if (m_fullscreenFullScreenButton) m_fullscreenFullScreenButton->setIsFullscreen(true); } void MediaControlsBlackBerry::exitedFullscreen() { m_panel->setCanBeDragged(false); m_embeddedPanel->setCanBeDragged(false); if (m_fullscreenFullScreenButton) m_fullscreenFullScreenButton->setIsFullscreen(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(); m_embeddedPanel->resetPosition(); MediaControls::exitedFullscreen(); } void MediaControlsBlackBerry::showVolumeSlider() { if (!m_mediaController->hasAudio()) return; if (m_volumeSliderContainer) m_volumeSliderContainer->show(); } void MediaControlsBlackBerry::toggleVolumeSlider() { if (!m_mediaController->hasAudio()) return; if (m_volumeSliderContainer) { if (m_volumeSliderContainer->renderer() && m_volumeSliderContainer->renderer()->visibleToHitTesting()) m_volumeSliderContainer->hide(); else m_volumeSliderContainer->show(); } } bool MediaControlsBlackBerry::shouldHideControls() { if (m_isFullscreen) return !m_panel->hovered(); return !m_embeddedPanel->hovered(); } } #endif