2 * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14 * its contributors may be used to endorse or promote products derived
15 * from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 #include "MediaControlElements.h"
35 #include "EventNames.h"
36 #include "FloatConversion.h"
38 #include "HTMLNames.h"
39 #include "LocalizedStrings.h"
40 #include "MouseEvent.h"
42 #include "RenderMedia.h"
43 #include "RenderSlider.h"
44 #include "RenderTheme.h"
49 using namespace HTMLNames;
51 HTMLMediaElement* toParentMediaElement(RenderObject* o)
53 Node* node = o->node();
54 Node* mediaNode = node ? node->shadowAncestorNode() : 0;
55 if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
58 return static_cast<HTMLMediaElement*>(mediaNode);
61 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
62 static const float cSeekRepeatDelay = 0.1f;
63 static const float cStepTime = 0.07f;
64 static const float cSeekTime = 0.2f;
66 inline MediaControlShadowRootElement::MediaControlShadowRootElement(HTMLMediaElement* mediaElement)
67 : HTMLDivElement(divTag, mediaElement->document())
69 setShadowHost(mediaElement);
72 PassRefPtr<MediaControlShadowRootElement> MediaControlShadowRootElement::create(HTMLMediaElement* mediaElement)
74 RefPtr<MediaControlShadowRootElement> element = adoptRef(new MediaControlShadowRootElement(mediaElement));
76 RefPtr<RenderStyle> rootStyle = RenderStyle::create();
77 rootStyle->inheritFrom(mediaElement->renderer()->style());
78 rootStyle->setDisplay(BLOCK);
79 rootStyle->setPosition(RelativePosition);
81 RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(element.get());
82 renderer->setStyle(rootStyle.release());
84 element->setRenderer(renderer);
85 element->setAttached();
86 element->setInDocument();
88 return element.release();
91 void MediaControlShadowRootElement::updateStyle()
94 RenderStyle* timelineContainerStyle = shadowHost()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
95 renderer()->setStyle(timelineContainerStyle);
99 void MediaControlShadowRootElement::detach()
101 HTMLDivElement::detach();
102 // FIXME: Remove once shadow DOM uses Element::setShadowRoot().
106 // ----------------------------
108 MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
109 : HTMLDivElement(divTag, mediaElement->document())
110 , m_mediaElement(mediaElement)
111 , m_pseudoStyleId(pseudo)
115 case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
116 m_displayType = MediaCurrentTimeDisplay;
118 case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
119 m_displayType = MediaTimeRemainingDisplay;
121 case MEDIA_CONTROLS_TIMELINE_CONTAINER:
122 m_displayType = MediaTimelineContainer;
124 case MEDIA_CONTROLS_STATUS_DISPLAY:
125 m_displayType = MediaStatusDisplay;
127 case MEDIA_CONTROLS_PANEL:
128 m_displayType = MediaControlsPanel;
130 case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
131 m_displayType = MediaVolumeSliderContainer;
134 ASSERT_NOT_REACHED();
139 PassRefPtr<MediaControlElement> MediaControlElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
141 return adoptRef(new MediaControlElement(mediaElement, pseudoStyleId));
144 void MediaControlElement::attachToParent(Element* parent)
146 // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here?
147 // We shouldn't be calling parser API methods outside of the parser!
148 parent->parserAddChild(this);
151 void MediaControlElement::update()
154 renderer()->updateFromElement();
158 PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
160 RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
164 // text-decoration can't be overrided from CSS. So we do it here.
165 // See https://bugs.webkit.org/show_bug.cgi?id=27015
166 style->setTextDecoration(TDNONE);
167 style->setTextDecorationsInEffect(TDNONE);
172 bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
174 ASSERT(document()->page());
176 return HTMLDivElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
177 && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
180 void MediaControlElement::attach()
182 RefPtr<RenderStyle> style = styleForElement();
185 bool needsRenderer = rendererIsNeeded(style.get());
188 RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
191 renderer->setStyle(style.get());
192 setRenderer(renderer);
193 if (parentNode() && parentNode()->renderer()) {
194 // Find next sibling with a renderer to determine where to insert.
195 Node* sibling = nextSibling();
196 while (sibling && !sibling->renderer())
197 sibling = sibling->nextSibling();
198 parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
200 ContainerNode::attach();
203 void MediaControlElement::updateStyle()
205 if (!m_mediaElement || !m_mediaElement->renderer())
208 RefPtr<RenderStyle> style = styleForElement();
212 bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
213 if (renderer() && !needsRenderer)
215 else if (!renderer() && needsRenderer)
217 else if (renderer()) {
218 renderer()->setStyle(style.get());
220 // Make sure that if there is any innerText renderer, it is updated as well.
221 if (firstChild() && firstChild()->renderer())
222 firstChild()->renderer()->setStyle(style.get());
226 // ----------------------------
228 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement)
229 : MediaControlElement(mediaElement, MEDIA_CONTROLS_TIMELINE_CONTAINER)
233 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement)
235 return adoptRef(new MediaControlTimelineContainerElement(mediaElement));
238 bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
240 if (!MediaControlElement::rendererIsNeeded(style))
243 // This is for MediaControllerThemeClassic:
244 // If there is no style for MediaControlStatusDisplayElement style, don't hide
246 if (!mediaElement()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY))
249 float duration = mediaElement()->duration();
250 return !isnan(duration) && !isinf(duration);
253 // ----------------------------
255 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
256 : MediaControlElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER)
263 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement)
265 return adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
268 PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
270 RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
271 style->setPosition(AbsolutePosition);
272 style->setLeft(Length(m_x, Fixed));
273 style->setTop(Length(m_y, Fixed));
274 style->setDisplay(m_isVisible ? BLOCK : NONE);
278 void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
280 if (visible == m_isVisible)
282 m_isVisible = visible;
285 void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
287 if (x == m_x && y == m_y)
293 bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
295 if (renderer() && renderer()->style()->hasAppearance())
296 return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
301 // ----------------------------
303 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement)
304 : MediaControlElement(mediaElement, MEDIA_CONTROLS_STATUS_DISPLAY)
305 , m_stateBeingDisplayed(Nothing)
309 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement)
311 return adoptRef(new MediaControlStatusDisplayElement(mediaElement));
314 void MediaControlStatusDisplayElement::update()
316 MediaControlElement::update();
318 // Get the new state that we'll have to display.
319 StateBeingDisplayed newStateToDisplay = Nothing;
321 if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty())
322 newStateToDisplay = Loading;
323 else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream)
324 newStateToDisplay = LiveBroadcast;
326 // Propagate only if needed.
327 if (newStateToDisplay == m_stateBeingDisplayed)
329 m_stateBeingDisplayed = newStateToDisplay;
332 switch (m_stateBeingDisplayed) {
337 setInnerText(mediaElementLoadingStateText(), e);
340 setInnerText(mediaElementLiveBroadcastStateText(), e);
345 bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
347 if (!MediaControlElement::rendererIsNeeded(style))
349 float duration = mediaElement()->duration();
350 return (isnan(duration) || isinf(duration));
353 // ----------------------------
355 MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
356 : HTMLInputElement(inputTag, mediaElement->document())
357 , m_mediaElement(mediaElement)
358 , m_pseudoStyleId(pseudo)
363 case MEDIA_CONTROLS_MUTE_BUTTON:
364 m_displayType = MediaMuteButton;
366 case MEDIA_CONTROLS_PLAY_BUTTON:
367 m_displayType = MediaPlayButton;
369 case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
370 m_displayType = MediaSeekForwardButton;
372 case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
373 m_displayType = MediaSeekBackButton;
375 case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
376 m_displayType = MediaFullscreenButton;
378 case MEDIA_CONTROLS_TIMELINE:
379 m_displayType = MediaSlider;
381 case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
382 m_displayType = MediaReturnToRealtimeButton;
384 case MEDIA_CONTROLS_REWIND_BUTTON:
385 m_displayType = MediaRewindButton;
387 case MEDIA_CONTROLS_VOLUME_SLIDER:
388 m_displayType = MediaVolumeSlider;
390 case MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON:
391 m_displayType = MediaVolumeSliderMuteButton;
393 case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
394 m_displayType = MediaShowClosedCaptionsButton;
397 ASSERT_NOT_REACHED();
402 void MediaControlInputElement::attachToParent(Element* parent)
404 // FIXME: This code seems very wrong. Why are we magically adding |this| to the DOM here?
405 // We shouldn't be calling parser API methods outside of the parser!
406 parent->parserAddChild(this);
409 void MediaControlInputElement::update()
413 renderer()->updateFromElement();
417 PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
419 return mediaElement()->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
422 bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
424 ASSERT(document()->page());
426 return HTMLInputElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
427 && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), mediaElement()));
430 void MediaControlInputElement::attach()
432 RefPtr<RenderStyle> style = styleForElement();
436 bool needsRenderer = rendererIsNeeded(style.get());
439 RenderObject* renderer = createRenderer(mediaElement()->renderer()->renderArena(), style.get());
442 renderer->setStyle(style.get());
443 setRenderer(renderer);
444 if (parentNode() && parentNode()->renderer()) {
445 // Find next sibling with a renderer to determine where to insert.
446 Node* sibling = nextSibling();
447 while (sibling && !sibling->renderer())
448 sibling = sibling->nextSibling();
449 parentNode()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
451 ContainerNode::attach();
452 // FIXME: Currently, MeidaControlInput circumvents the normal attachment
453 // and style recalc cycle and thus we need to add extra logic to be aware of
454 // the shadow DOM. Remove this once all media controls are transitioned to use the regular
455 // style calculation.
456 if (Node* shadowNode = shadowRoot())
457 shadowNode->attach();
460 void MediaControlInputElement::updateStyle()
462 if (!mediaElement() || !mediaElement()->renderer())
465 RefPtr<RenderStyle> style = styleForElement();
469 bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
470 if (renderer() && !needsRenderer)
472 else if (!renderer() && needsRenderer)
475 renderer()->setStyle(style.get());
477 // FIXME: Currently, MeidaControlInput circumvents the normal attachment
478 // and style recalc cycle and thus we need to add extra logic to be aware of
479 // the shadow DOM. Remove this once all media controls are transitioned to use
480 // the new shadow DOM.
481 if (Node* shadowNode = shadowRoot())
482 shadowNode->recalcStyle(Node::Force);
485 bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
487 if (renderer() && renderer()->style()->hasAppearance())
488 return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
493 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
495 if (displayType == m_displayType)
498 m_displayType = displayType;
499 if (RenderObject* object = renderer())
503 // ----------------------------
505 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, ButtonLocation location)
506 : MediaControlInputElement(mediaElement, location == Controller ? MEDIA_CONTROLS_MUTE_BUTTON : MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON)
510 PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement, ButtonLocation location)
512 RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, location));
513 button->setType("button");
514 return button.release();
517 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
519 if (event->type() == eventNames().clickEvent) {
520 mediaElement()->setMuted(!mediaElement()->muted());
521 event->setDefaultHandled();
523 HTMLInputElement::defaultEventHandler(event);
526 void MediaControlMuteButtonElement::updateDisplayType()
528 setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton);
531 // ----------------------------
533 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement)
534 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_PLAY_BUTTON)
538 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement)
540 RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement));
541 button->setType("button");
542 return button.release();
545 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
547 if (event->type() == eventNames().clickEvent) {
548 mediaElement()->togglePlayState();
549 event->setDefaultHandled();
551 HTMLInputElement::defaultEventHandler(event);
554 void MediaControlPlayButtonElement::updateDisplayType()
556 setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton);
559 // ----------------------------
561 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, PseudoId pseudoId)
562 : MediaControlInputElement(mediaElement, pseudoId)
565 , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
569 PassRefPtr<MediaControlSeekButtonElement> MediaControlSeekButtonElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
571 RefPtr<MediaControlSeekButtonElement> button = adoptRef(new MediaControlSeekButtonElement(mediaElement, pseudoStyleId));
572 button->setType("button");
573 return button.release();
576 inline bool MediaControlSeekButtonElement::isForwardButton() const
578 return pseudoStyleId() == MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
581 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
583 if (event->type() == eventNames().mousedownEvent) {
584 if (Frame* frame = document()->frame()) {
586 frame->eventHandler()->setCapturingMouseEventsNode(this);
588 mediaElement()->pause(event->fromUserGesture());
589 m_seekTimer.startRepeating(cSeekRepeatDelay);
590 event->setDefaultHandled();
591 } else if (event->type() == eventNames().mouseupEvent) {
593 if (Frame* frame = document()->frame()) {
595 frame->eventHandler()->setCapturingMouseEventsNode(0);
598 if (m_seeking || m_seekTimer.isActive()) {
600 float stepTime = isForwardButton() ? cStepTime : -cStepTime;
601 mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec);
605 event->setDefaultHandled();
608 HTMLInputElement::defaultEventHandler(event);
611 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
615 float seekTime = isForwardButton() ? cSeekTime : -cSeekTime;
616 mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec);
619 void MediaControlSeekButtonElement::detach()
622 if (Frame* frame = document()->frame())
623 frame->eventHandler()->setCapturingMouseEventsNode(0);
625 MediaControlInputElement::detach();
628 // ----------------------------
630 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element)
631 : MediaControlInputElement(element, MEDIA_CONTROLS_REWIND_BUTTON)
635 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement)
637 RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement));
638 button->setType("button");
639 return button.release();
642 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
644 if (event->type() == eventNames().clickEvent) {
645 mediaElement()->rewind(30);
646 event->setDefaultHandled();
648 HTMLInputElement::defaultEventHandler(event);
651 // ----------------------------
653 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement)
654 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON)
658 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement)
660 RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement));
661 button->setType("button");
662 return button.release();
665 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
667 if (event->type() == eventNames().clickEvent) {
668 mediaElement()->returnToRealtime();
669 event->setDefaultHandled();
671 HTMLInputElement::defaultEventHandler(event);
675 // ----------------------------
677 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement)
678 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON)
682 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement)
684 RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement));
685 button->setType("button");
686 return button.release();
689 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
691 if (event->type() == eventNames().clickEvent) {
692 mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
693 setChecked(mediaElement()->closedCaptionsVisible());
694 event->setDefaultHandled();
696 HTMLInputElement::defaultEventHandler(event);
699 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
701 setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
704 // ----------------------------
706 MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement)
707 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TIMELINE)
711 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement)
713 RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement));
714 timeline->setType("range");
715 return timeline.release();
718 void MediaControlTimelineElement::defaultEventHandler(Event* event)
720 // Left button is 0. Rejects mouse events not from left button.
721 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
727 if (event->type() == eventNames().mousedownEvent)
728 mediaElement()->beginScrubbing();
730 MediaControlInputElement::defaultEventHandler(event);
732 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
735 float time = narrowPrecisionToFloat(value().toDouble());
736 if (time != mediaElement()->currentTime()) {
738 mediaElement()->setCurrentTime(time, ec);
741 RenderSlider* slider = toRenderSlider(renderer());
742 if (slider && slider->inDragMode())
743 toRenderMedia(mediaElement()->renderer())->updateTimeDisplay();
745 if (event->type() == eventNames().mouseupEvent)
746 mediaElement()->endScrubbing();
749 void MediaControlTimelineElement::update(bool updateDuration)
751 if (updateDuration) {
752 float duration = mediaElement()->duration();
753 setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
755 setValue(String::number(mediaElement()->currentTime()));
756 MediaControlInputElement::update();
759 // ----------------------------
761 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement)
762 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER)
766 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement)
768 RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
769 slider->setType("range");
770 return slider.release();
773 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
775 // Left button is 0. Rejects mouse events not from left button.
776 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
782 MediaControlInputElement::defaultEventHandler(event);
784 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
787 float volume = narrowPrecisionToFloat(value().toDouble());
788 if (volume != mediaElement()->volume()) {
789 ExceptionCode ec = 0;
790 mediaElement()->setVolume(volume, ec);
795 void MediaControlVolumeSliderElement::update()
797 float volume = mediaElement()->volume();
798 if (value().toFloat() != volume)
799 setValue(String::number(volume));
800 MediaControlInputElement::update();
803 // ----------------------------
805 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement)
806 : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_FULLSCREEN_BUTTON)
810 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement)
812 RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement));
813 button->setType("button");
814 return button.release();
817 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
819 if (event->type() == eventNames().clickEvent) {
820 #if ENABLE(FULLSCREEN_API)
821 // Only use the new full screen API if the fullScreenEnabled setting has
822 // been explicitly enabled. Otherwise, use the old fullscreen API. This
823 // allows apps which embed a WebView to retain the existing full screen
824 // video implementation without requiring them to implement their own full
826 if (document()->settings() && document()->settings()->fullScreenEnabled()) {
827 if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement())
828 document()->webkitCancelFullScreen();
830 mediaElement()->webkitRequestFullScreen(0);
833 mediaElement()->enterFullscreen();
834 event->setDefaultHandled();
836 HTMLInputElement::defaultEventHandler(event);
839 // ----------------------------
841 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
842 : MediaControlElement(mediaElement, pseudo)
848 PassRefPtr<MediaControlTimeDisplayElement> MediaControlTimeDisplayElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
850 return adoptRef(new MediaControlTimeDisplayElement(mediaElement, pseudoStyleId));
853 PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
855 RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
857 style = RenderStyle::clone(style.get());
858 style->setWidth(Length(0, Fixed));
863 void MediaControlTimeDisplayElement::setVisible(bool visible)
865 if (visible == m_isVisible)
867 m_isVisible = visible;
869 // This function is used during the RenderMedia::layout()
870 // call, where we cannot change the renderer at this time.
871 if (!renderer() || !renderer()->style())
874 RefPtr<RenderStyle> style = styleForElement();
875 renderer()->setStyle(style.get());
878 void MediaControlTimeDisplayElement::setCurrentValue(float time)
880 m_currentValue = time;
883 } // namespace WebCore
885 #endif // ENABLE(VIDEO)