e5e5ae58b6c1ee74b9ab999b14e83cc6bc697474
[WebKit.git] / Source / WebCore / rendering / MediaControlElements.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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.
16  *
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.
27  */
28
29 #include "config.h"
30
31 #if ENABLE(VIDEO)
32
33 #include "MediaControlElements.h"
34
35 #include "EventNames.h"
36 #include "FloatConversion.h"
37 #include "Frame.h"
38 #include "HTMLNames.h"
39 #include "LocalizedStrings.h"
40 #include "MouseEvent.h"
41 #include "Page.h"
42 #include "RenderMedia.h"
43 #include "RenderSlider.h"
44 #include "RenderTheme.h"
45 #include "Settings.h"
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50
51 HTMLMediaElement* toParentMediaElement(RenderObject* o)
52 {
53     Node* node = o->node();
54     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
55     if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
56         return 0;
57
58     return static_cast<HTMLMediaElement*>(mediaNode);
59 }
60
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;
65
66 inline MediaControlShadowRootElement::MediaControlShadowRootElement(HTMLMediaElement* mediaElement)
67     : HTMLDivElement(divTag, mediaElement->document())
68 {
69     setShadowHost(mediaElement);
70 }
71
72 PassRefPtr<MediaControlShadowRootElement> MediaControlShadowRootElement::create(HTMLMediaElement* mediaElement)
73 {
74     RefPtr<MediaControlShadowRootElement> element = adoptRef(new MediaControlShadowRootElement(mediaElement));
75
76     RefPtr<RenderStyle> rootStyle = RenderStyle::create();
77     rootStyle->inheritFrom(mediaElement->renderer()->style());
78     rootStyle->setDisplay(BLOCK);
79     rootStyle->setPosition(RelativePosition);
80
81     RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(element.get());
82     renderer->setStyle(rootStyle.release());
83
84     element->setRenderer(renderer);
85     element->setAttached();
86     element->setInDocument();
87
88     return element.release();
89 }
90
91 void MediaControlShadowRootElement::updateStyle()
92 {
93     if (renderer()) {
94         RenderStyle* timelineContainerStyle = shadowHost()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
95         renderer()->setStyle(timelineContainerStyle);
96     }
97 }
98
99 void MediaControlShadowRootElement::detach()
100 {
101     HTMLDivElement::detach();
102     // FIXME: Remove once shadow DOM uses Element::setShadowRoot().
103     setShadowHost(0);
104 }
105
106 // ----------------------------
107
108 MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
109     : HTMLDivElement(divTag, mediaElement->document())
110     , m_mediaElement(mediaElement)
111     , m_pseudoStyleId(pseudo)
112 {
113     setInDocument();
114     switch (pseudo) {
115     case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
116         m_displayType = MediaCurrentTimeDisplay;
117         break;
118     case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
119         m_displayType = MediaTimeRemainingDisplay;
120         break;
121     case MEDIA_CONTROLS_TIMELINE_CONTAINER:
122         m_displayType = MediaTimelineContainer;
123         break;
124     case MEDIA_CONTROLS_STATUS_DISPLAY:
125         m_displayType = MediaStatusDisplay;
126         break;
127     case MEDIA_CONTROLS_PANEL:
128         m_displayType = MediaControlsPanel;
129         break;
130     case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
131         m_displayType = MediaVolumeSliderContainer;
132         break;
133     default:
134         ASSERT_NOT_REACHED();
135         break;
136     }
137 }
138
139 PassRefPtr<MediaControlElement> MediaControlElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
140 {
141     return adoptRef(new MediaControlElement(mediaElement, pseudoStyleId));
142 }
143
144 void MediaControlElement::attachToParent(Element* parent)
145 {
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);
149 }
150
151 void MediaControlElement::update()
152 {
153     if (renderer())
154         renderer()->updateFromElement();
155     updateStyle();
156 }
157
158 PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
159 {
160     RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
161     if (!style)
162         return 0;
163     
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);
168
169     return style;
170 }
171
172 bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
173 {
174     ASSERT(document()->page());
175
176     return HTMLDivElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
177         && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
178 }
179     
180 void MediaControlElement::attach()
181 {
182     RefPtr<RenderStyle> style = styleForElement();
183     if (!style)
184         return;
185     bool needsRenderer = rendererIsNeeded(style.get());
186     if (!needsRenderer)
187         return;
188     RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
189     if (!renderer)
190         return;
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);
199     }
200     ContainerNode::attach();
201 }
202
203 void MediaControlElement::updateStyle()
204 {
205     if (!m_mediaElement || !m_mediaElement->renderer())
206         return;
207
208     RefPtr<RenderStyle> style = styleForElement();
209     if (!style)
210         return;
211
212     bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
213     if (renderer() && !needsRenderer)
214         detach();
215     else if (!renderer() && needsRenderer)
216         attach();
217     else if (renderer()) {
218         renderer()->setStyle(style.get());
219
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());
223     }
224 }
225
226 // ----------------------------
227
228 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement)
229     : MediaControlElement(mediaElement, MEDIA_CONTROLS_TIMELINE_CONTAINER)
230 {
231 }
232
233 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement)
234 {
235     return adoptRef(new MediaControlTimelineContainerElement(mediaElement));
236 }
237
238 bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
239 {
240     if (!MediaControlElement::rendererIsNeeded(style))
241         return false;
242
243     // This is for MediaControllerThemeClassic:
244     // If there is no style for MediaControlStatusDisplayElement style, don't hide
245     // the timeline.
246     if (!mediaElement()->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY))
247         return true;
248
249     float duration = mediaElement()->duration();
250     return !isnan(duration) && !isinf(duration);
251 }
252
253 // ----------------------------
254
255 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
256     : MediaControlElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER)
257     , m_isVisible(false)
258     , m_x(0)
259     , m_y(0)
260 {
261 }
262
263 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement)
264 {
265     return adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
266 }
267
268 PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
269 {
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);
275     return style;
276 }
277
278 void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
279 {
280     if (visible == m_isVisible)
281         return;
282     m_isVisible = visible;
283 }
284
285 void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
286 {
287     if (x == m_x && y == m_y)
288         return;
289     m_x = x;
290     m_y = y;
291 }
292
293 bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
294 {
295     if (renderer() && renderer()->style()->hasAppearance())
296         return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
297
298     return false;
299 }
300
301 // ----------------------------
302
303 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement)
304     : MediaControlElement(mediaElement, MEDIA_CONTROLS_STATUS_DISPLAY)
305     , m_stateBeingDisplayed(Nothing)
306 {
307 }
308
309 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement)
310 {
311     return adoptRef(new MediaControlStatusDisplayElement(mediaElement));
312 }
313
314 void MediaControlStatusDisplayElement::update()
315 {
316     MediaControlElement::update();
317
318     // Get the new state that we'll have to display.
319     StateBeingDisplayed newStateToDisplay = Nothing;
320
321     if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty())
322         newStateToDisplay = Loading;
323     else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream)
324         newStateToDisplay = LiveBroadcast;
325
326     // Propagate only if needed.
327     if (newStateToDisplay == m_stateBeingDisplayed)
328         return;
329     m_stateBeingDisplayed = newStateToDisplay;
330
331     ExceptionCode e;
332     switch (m_stateBeingDisplayed) {
333     case Nothing:
334         setInnerText("", e);
335         break;
336     case Loading:
337         setInnerText(mediaElementLoadingStateText(), e);
338         break;
339     case LiveBroadcast:
340         setInnerText(mediaElementLiveBroadcastStateText(), e);
341         break;
342     }
343 }
344
345 bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
346 {
347     if (!MediaControlElement::rendererIsNeeded(style))
348         return false;
349     float duration = mediaElement()->duration();
350     return (isnan(duration) || isinf(duration));
351 }
352
353 // ----------------------------
354     
355 MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
356     : HTMLInputElement(inputTag, mediaElement->document())
357     , m_mediaElement(mediaElement)
358     , m_pseudoStyleId(pseudo)
359 {
360     setInDocument();
361
362     switch (pseudo) {
363     case MEDIA_CONTROLS_MUTE_BUTTON:
364         m_displayType = MediaMuteButton;
365         break;
366     case MEDIA_CONTROLS_PLAY_BUTTON:
367         m_displayType = MediaPlayButton;
368         break;
369     case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
370         m_displayType = MediaSeekForwardButton;
371         break;
372     case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
373         m_displayType = MediaSeekBackButton;
374         break;
375     case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
376         m_displayType = MediaFullscreenButton;
377         break;
378     case MEDIA_CONTROLS_TIMELINE:
379         m_displayType = MediaSlider;
380         break;
381     case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
382         m_displayType = MediaReturnToRealtimeButton;
383         break;
384     case MEDIA_CONTROLS_REWIND_BUTTON:
385         m_displayType = MediaRewindButton;
386         break;
387     case MEDIA_CONTROLS_VOLUME_SLIDER:
388         m_displayType = MediaVolumeSlider;
389         break;
390     case MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON:
391         m_displayType = MediaVolumeSliderMuteButton;
392         break;
393     case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
394         m_displayType = MediaShowClosedCaptionsButton;
395         break;
396     default:
397         ASSERT_NOT_REACHED();
398         break;
399     }
400 }
401
402 void MediaControlInputElement::attachToParent(Element* parent)
403 {
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);
407 }
408
409 void MediaControlInputElement::update()
410 {
411     updateDisplayType();
412     if (renderer())
413         renderer()->updateFromElement();
414     updateStyle();
415 }
416
417 PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
418 {
419     return mediaElement()->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
420 }
421
422 bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
423 {
424     ASSERT(document()->page());
425
426     return HTMLInputElement::rendererIsNeeded(style) && parentNode() && parentNode()->renderer()
427         && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), mediaElement()));
428 }
429
430 void MediaControlInputElement::attach()
431 {
432     RefPtr<RenderStyle> style = styleForElement();
433     if (!style)
434         return;
435     
436     bool needsRenderer = rendererIsNeeded(style.get());
437     if (!needsRenderer)
438         return;
439     RenderObject* renderer = createRenderer(mediaElement()->renderer()->renderArena(), style.get());
440     if (!renderer)
441         return;
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);
450     }  
451     ContainerNode::attach();
452 }
453
454 void MediaControlInputElement::updateStyle()
455 {
456     if (!mediaElement() || !mediaElement()->renderer())
457         return;
458     
459     RefPtr<RenderStyle> style = styleForElement();
460     if (!style)
461         return;
462     
463     bool needsRenderer = rendererIsNeeded(style.get()) && parentNode() && parentNode()->renderer();
464     if (renderer() && !needsRenderer)
465         detach();
466     else if (!renderer() && needsRenderer)
467         attach();
468     else if (renderer())
469         renderer()->setStyle(style.get());
470 }
471     
472 bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
473 {
474     if (renderer() && renderer()->style()->hasAppearance())
475         return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
476
477     return false;
478 }
479
480 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
481 {
482     if (displayType == m_displayType)
483         return;
484
485     m_displayType = displayType;
486     if (RenderObject* object = renderer())
487         object->repaint();
488 }
489
490 // ----------------------------
491
492 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, ButtonLocation location)
493     : MediaControlInputElement(mediaElement, location == Controller ? MEDIA_CONTROLS_MUTE_BUTTON : MEDIA_CONTROLS_VOLUME_SLIDER_MUTE_BUTTON)
494 {
495 }
496
497 PassRefPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(HTMLMediaElement* mediaElement, ButtonLocation location)
498 {
499     RefPtr<MediaControlMuteButtonElement> button = adoptRef(new MediaControlMuteButtonElement(mediaElement, location));
500     button->setType("button");
501     return button.release();
502 }
503
504 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
505 {
506     if (event->type() == eventNames().clickEvent) {
507         mediaElement()->setMuted(!mediaElement()->muted());
508         event->setDefaultHandled();
509     }
510     HTMLInputElement::defaultEventHandler(event);
511 }
512
513 void MediaControlMuteButtonElement::updateDisplayType()
514 {
515     setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton);
516 }
517
518 // ----------------------------
519
520 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement)
521     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_PLAY_BUTTON)
522 {
523 }
524
525 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement)
526 {
527     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement));
528     button->setType("button");
529     return button.release();
530 }
531
532 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
533 {
534     if (event->type() == eventNames().clickEvent) {
535         mediaElement()->togglePlayState();
536         event->setDefaultHandled();
537     }
538     HTMLInputElement::defaultEventHandler(event);
539 }
540
541 void MediaControlPlayButtonElement::updateDisplayType()
542 {
543     setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton);
544 }
545
546 // ----------------------------
547
548 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, PseudoId pseudoId)
549     : MediaControlInputElement(mediaElement, pseudoId)
550     , m_seeking(false)
551     , m_capturing(false)
552     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
553 {
554 }
555
556 PassRefPtr<MediaControlSeekButtonElement> MediaControlSeekButtonElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
557 {
558     RefPtr<MediaControlSeekButtonElement> button = adoptRef(new MediaControlSeekButtonElement(mediaElement, pseudoStyleId));
559     button->setType("button");
560     return button.release();
561 }
562
563 inline bool MediaControlSeekButtonElement::isForwardButton() const
564 {
565     return pseudoStyleId() == MEDIA_CONTROLS_SEEK_FORWARD_BUTTON;
566 }
567
568 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
569 {
570     if (event->type() == eventNames().mousedownEvent) {
571         if (Frame* frame = document()->frame()) {
572             m_capturing = true;
573             frame->eventHandler()->setCapturingMouseEventsNode(this);
574         }
575         mediaElement()->pause(event->fromUserGesture());
576         m_seekTimer.startRepeating(cSeekRepeatDelay);
577         event->setDefaultHandled();
578     } else if (event->type() == eventNames().mouseupEvent) {
579         if (m_capturing)
580             if (Frame* frame = document()->frame()) {
581                 m_capturing = false;
582                 frame->eventHandler()->setCapturingMouseEventsNode(0);
583             }
584         ExceptionCode ec;
585         if (m_seeking || m_seekTimer.isActive()) {
586             if (!m_seeking) {
587                 float stepTime = isForwardButton() ? cStepTime : -cStepTime;
588                 mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec);
589             }
590             m_seekTimer.stop();
591             m_seeking = false;
592             event->setDefaultHandled();
593         }
594     }
595     HTMLInputElement::defaultEventHandler(event);
596 }
597
598 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
599 {
600     ExceptionCode ec;
601     m_seeking = true;
602     float seekTime = isForwardButton() ? cSeekTime : -cSeekTime;
603     mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec);
604 }
605
606 void MediaControlSeekButtonElement::detach()
607 {
608     if (m_capturing) {
609         if (Frame* frame = document()->frame())
610             frame->eventHandler()->setCapturingMouseEventsNode(0);      
611     }
612     MediaControlInputElement::detach();
613 }
614
615 // ----------------------------
616
617 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element)
618     : MediaControlInputElement(element, MEDIA_CONTROLS_REWIND_BUTTON)
619 {
620 }
621
622 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement)
623 {
624     RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement));
625     button->setType("button");
626     return button.release();
627 }
628
629 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
630 {
631     if (event->type() == eventNames().clickEvent) {
632         mediaElement()->rewind(30);
633         event->setDefaultHandled();
634     }    
635     HTMLInputElement::defaultEventHandler(event);
636 }
637
638 // ----------------------------
639
640 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement)
641     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON)
642 {
643 }
644
645 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement)
646 {
647     RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement));
648     button->setType("button");
649     return button.release();
650 }
651
652 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
653 {
654     if (event->type() == eventNames().clickEvent) {
655         mediaElement()->returnToRealtime();
656         event->setDefaultHandled();
657     }
658     HTMLInputElement::defaultEventHandler(event);
659 }
660
661
662 // ----------------------------
663
664 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement)
665     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON)
666 {
667 }
668
669 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement)
670 {
671     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement));
672     button->setType("button");
673     return button.release();
674 }
675
676 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
677 {
678     if (event->type() == eventNames().clickEvent) {
679         mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
680         setChecked(mediaElement()->closedCaptionsVisible());
681         event->setDefaultHandled();
682     }
683     HTMLInputElement::defaultEventHandler(event);
684 }
685
686 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
687 {
688     setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
689 }
690
691 // ----------------------------
692
693 MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement)
694     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_TIMELINE)
695 {
696 }
697
698 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement)
699 {
700     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement));
701     timeline->setType("range");
702     return timeline.release();
703 }
704
705 void MediaControlTimelineElement::defaultEventHandler(Event* event)
706 {
707     // Left button is 0. Rejects mouse events not from left button.
708     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
709         return;
710
711     if (!attached())
712         return;
713
714     if (event->type() == eventNames().mousedownEvent)
715         mediaElement()->beginScrubbing();
716
717     MediaControlInputElement::defaultEventHandler(event);
718
719     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
720         return;
721
722     float time = narrowPrecisionToFloat(value().toDouble());
723     if (time != mediaElement()->currentTime()) {
724         ExceptionCode ec;
725         mediaElement()->setCurrentTime(time, ec);
726     }
727
728     RenderSlider* slider = toRenderSlider(renderer());
729     if (slider && slider->inDragMode())
730         toRenderMedia(mediaElement()->renderer())->updateTimeDisplay();
731
732     if (event->type() == eventNames().mouseupEvent)
733         mediaElement()->endScrubbing();
734 }
735
736 void MediaControlTimelineElement::update(bool updateDuration) 
737 {
738     if (updateDuration) {
739         float duration = mediaElement()->duration();
740         setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
741     }
742     setValue(String::number(mediaElement()->currentTime()));
743     MediaControlInputElement::update();
744 }
745
746 // ----------------------------
747
748 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement)
749     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_VOLUME_SLIDER)
750 {
751 }
752
753 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement)
754 {
755     RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
756     slider->setType("range");
757     return slider.release();
758 }
759
760 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
761 {
762     // Left button is 0. Rejects mouse events not from left button.
763     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
764         return;
765
766     if (!attached())
767         return;
768
769     MediaControlInputElement::defaultEventHandler(event);
770
771     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
772         return;
773
774     float volume = narrowPrecisionToFloat(value().toDouble());
775     if (volume != mediaElement()->volume()) {
776         ExceptionCode ec = 0;
777         mediaElement()->setVolume(volume, ec);
778         ASSERT(!ec);
779     }
780 }
781
782 void MediaControlVolumeSliderElement::update()
783 {
784     float volume = mediaElement()->volume();
785     if (value().toFloat() != volume)
786         setValue(String::number(volume));
787     MediaControlInputElement::update();
788 }
789
790 // ----------------------------
791
792 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement)
793     : MediaControlInputElement(mediaElement, MEDIA_CONTROLS_FULLSCREEN_BUTTON)
794 {
795 }
796
797 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement)
798 {
799     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement));
800     button->setType("button");
801     return button.release();
802 }
803
804 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
805 {
806     if (event->type() == eventNames().clickEvent) {
807 #if ENABLE(FULLSCREEN_API)
808         // Only use the new full screen API if the fullScreenEnabled setting has 
809         // been explicitly enabled.  Otherwise, use the old fullscreen API.  This
810         // allows apps which embed a WebView to retain the existing full screen
811         // video implementation without requiring them to implement their own full 
812         // screen behavior.
813         if (document()->settings() && document()->settings()->fullScreenEnabled()) {
814             if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement())
815                 document()->webkitCancelFullScreen();
816             else
817                 mediaElement()->webkitRequestFullScreen(0);
818         } else
819 #endif
820             mediaElement()->enterFullscreen();
821         event->setDefaultHandled();
822     }
823     HTMLInputElement::defaultEventHandler(event);
824 }
825
826 // ----------------------------
827
828 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement, PseudoId pseudo)
829     : MediaControlElement(mediaElement, pseudo)
830     , m_currentValue(0)
831     , m_isVisible(true)
832 {
833 }
834
835 PassRefPtr<MediaControlTimeDisplayElement> MediaControlTimeDisplayElement::create(HTMLMediaElement* mediaElement, PseudoId pseudoStyleId)
836 {
837     return adoptRef(new MediaControlTimeDisplayElement(mediaElement, pseudoStyleId));
838 }
839
840 PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
841 {
842     RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
843     if (!m_isVisible) {
844         style = RenderStyle::clone(style.get());
845         style->setWidth(Length(0, Fixed));
846     }
847     return style;
848 }
849
850 void MediaControlTimeDisplayElement::setVisible(bool visible)
851 {
852     if (visible == m_isVisible)
853         return;
854     m_isVisible = visible;
855
856     // This function is used during the RenderMedia::layout()
857     // call, where we cannot change the renderer at this time.
858     if (!renderer() || !renderer()->style())
859         return;
860
861     RefPtr<RenderStyle> style = styleForElement();
862     renderer()->setStyle(style.get());
863 }
864
865 void MediaControlTimeDisplayElement::setCurrentValue(float time)
866 {
867     m_currentValue = time;
868 }
869
870 } // namespace WebCore
871
872 #endif // ENABLE(VIDEO)