Revert "Video pause button does not work in video streaming from nytimes.com"
[framework/web/webkit-efl.git] / Source / WebCore / html / shadow / MediaControlElements.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 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 "CSSStyleDeclaration.h"
36 #include "CSSValueKeywords.h"
37 #include "DOMTokenList.h"
38 #include "EventNames.h"
39 #include "FloatConversion.h"
40 #include "FloatPoint.h"
41 #include "Frame.h"
42 #include "HTMLDivElement.h"
43 #include "HTMLMediaElement.h"
44 #include "HTMLNames.h"
45 #include "HTMLVideoElement.h"
46 #include "LayoutRepainter.h"
47 #include "LocalizedStrings.h"
48 #include "MediaControls.h"
49 #include "MouseEvent.h"
50 #include "Page.h"
51 #include "RenderDeprecatedFlexibleBox.h"
52 #include "RenderInline.h"
53 #include "RenderMedia.h"
54 #include "RenderSlider.h"
55 #include "RenderText.h"
56 #include "RenderTheme.h"
57 #include "RenderVideo.h"
58 #include "RenderView.h"
59 #include "ScriptController.h"
60 #include "Settings.h"
61 #include "StyleResolver.h"
62 #include "Text.h"
63
64 namespace WebCore {
65
66 using namespace HTMLNames;
67 using namespace std;
68
69 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
70
71 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
72 static const float cSeekForwardTime = 5.0f;
73 static const float cSeekBackTime = (-5.0f);
74 #endif
75 static const float cSkipRepeatDelay = 0.1f;
76 static const float cSkipTime = 0.2f;
77
78 static const float cScanRepeatDelay = 1.5f;
79 static const float cScanMaximumRate = 8;
80
81 HTMLMediaElement* toParentMediaElement(Node* node)
82 {
83     if (!node)
84         return 0;
85     Node* mediaNode = node->shadowHost();
86     if (!mediaNode)
87         mediaNode = node;
88     if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
89         return 0;
90
91     return static_cast<HTMLMediaElement*>(mediaNode);
92 }
93
94 MediaControlElementType mediaControlElementType(Node* node)
95 {
96     ASSERT(node->isMediaControlElement());
97     HTMLElement* element = toHTMLElement(node);
98     if (element->hasTagName(inputTag))
99         return static_cast<MediaControlInputElement*>(element)->displayType();
100     return static_cast<MediaControlElement*>(element)->displayType();
101 }
102
103 // ----------------------------
104
105 MediaControlElement::MediaControlElement(Document* document)
106     : HTMLDivElement(divTag, document)
107     , m_mediaController(0)
108 {
109 }
110
111 void MediaControlElement::show()
112 {
113     removeInlineStyleProperty(CSSPropertyDisplay);
114 }
115
116 void MediaControlElement::hide()
117 {
118     setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
119 }
120
121 // ----------------------------
122
123 inline MediaControlPanelElement::MediaControlPanelElement(Document* document)
124     : MediaControlElement(document)
125     , m_canBeDragged(false)
126     , m_isBeingDragged(false)
127     , m_isDisplayed(false)
128     , m_opaque(true)
129     , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
130 {
131 }
132
133 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document* document)
134 {
135     return adoptRef(new MediaControlPanelElement(document));
136 }
137
138 MediaControlElementType MediaControlPanelElement::displayType() const
139 {
140     return MediaControlsPanel;
141 }
142
143 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
144 {
145     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel"));
146     return id;
147 }
148
149 void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
150 {
151     if (!m_canBeDragged)
152         return;
153
154     if (m_isBeingDragged)
155         return;
156
157     RenderObject* renderer = this->renderer();
158     if (!renderer || !renderer->isBox())
159         return;
160
161     Frame* frame = document()->frame();
162     if (!frame)
163         return;
164
165     m_dragStartEventLocation = eventLocation;
166
167     frame->eventHandler()->setCapturingMouseEventsNode(this);
168
169     m_isBeingDragged = true;
170 }
171
172 void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
173 {
174     if (!m_isBeingDragged)
175         return;
176
177     LayoutSize distanceDragged = eventLocation - m_dragStartEventLocation;
178     setPosition(LayoutPoint(distanceDragged.width(), distanceDragged.height()));
179 }
180
181 void MediaControlPanelElement::endDrag()
182 {
183     if (!m_isBeingDragged)
184         return;
185
186     m_isBeingDragged = false;
187
188     Frame* frame = document()->frame();
189     if (!frame)
190         return;
191
192     frame->eventHandler()->setCapturingMouseEventsNode(0);
193 }
194
195 void MediaControlPanelElement::startTimer()
196 {
197     stopTimer();
198
199     // The timer is required to set the property display:'none' on the panel,
200     // such that captions are correctly displayed at the bottom of the video
201     // at the end of the fadeout transition.
202     double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
203     m_transitionTimer.startOneShot(duration);
204 }
205
206 void MediaControlPanelElement::stopTimer()
207 {
208     if (m_transitionTimer.isActive())
209         m_transitionTimer.stop();
210 }
211
212
213 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
214 {
215     if (!m_opaque)
216         hide();
217
218     stopTimer();
219 }
220
221 void MediaControlPanelElement::setPosition(const LayoutPoint& position)
222 {
223     double left = position.x();
224     double top = position.y();
225
226     // Set the left and top to control the panel's position; this depends on it being absolute positioned.
227     // Set the margin to zero since the position passed in will already include the effect of the margin.
228     setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
229     setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
230     setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
231     setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
232
233     ExceptionCode ignored;
234     classList()->add("dragged", ignored);
235 }
236
237 void MediaControlPanelElement::resetPosition()
238 {
239     removeInlineStyleProperty(CSSPropertyLeft);
240     removeInlineStyleProperty(CSSPropertyTop);
241     removeInlineStyleProperty(CSSPropertyMarginLeft);
242     removeInlineStyleProperty(CSSPropertyMarginTop);
243
244     ExceptionCode ignored;
245     classList()->remove("dragged", ignored);
246 }
247
248 void MediaControlPanelElement::makeOpaque()
249 {
250     if (m_opaque)
251         return;
252
253     double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0;
254
255     setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
256     setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
257     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
258
259     m_opaque = true;
260
261     if (m_isDisplayed)
262         show();
263 }
264
265 void MediaControlPanelElement::makeTransparent()
266 {
267     if (!m_opaque)
268         return;
269
270     setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
271     setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, document()->page()->theme()->mediaControlsFadeOutDuration(), CSSPrimitiveValue::CSS_S);
272     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
273
274     m_opaque = false;
275     startTimer();
276 }
277
278 void MediaControlPanelElement::defaultEventHandler(Event* event)
279 {
280     MediaControlElement::defaultEventHandler(event);
281
282     if (event->isMouseEvent()) {
283         LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation();
284         if (event->type() == eventNames().mousedownEvent && event->target() == this) {
285             startDrag(location);
286             event->setDefaultHandled();
287         } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
288             continueDrag(location);
289         else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
290             continueDrag(location);
291             endDrag();
292             event->setDefaultHandled();
293         }
294     }
295 }
296
297 void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
298 {
299     if (m_canBeDragged == canBeDragged)
300         return;
301
302     m_canBeDragged = canBeDragged;
303
304     if (!canBeDragged)
305         endDrag();
306 }
307
308 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
309 {
310     m_isDisplayed = isDisplayed;
311 }
312
313 // ----------------------------
314
315 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document)
316     : MediaControlElement(document)
317 {
318 }
319
320 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(Document* document)
321 {
322     RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(document));
323     element->hide();
324     return element.release();
325 }
326
327 MediaControlElementType MediaControlTimelineContainerElement::displayType() const
328 {
329     return MediaTimelineContainer;
330 }
331
332 const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
333 {
334     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container"));
335     return id;
336 }
337
338 // ----------------------------
339
340 class RenderMediaVolumeSliderContainer : public RenderBlock {
341 public:
342     RenderMediaVolumeSliderContainer(Node*);
343
344 private:
345     virtual void layout();
346 };
347
348 RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
349     : RenderBlock(node)
350 {
351 }
352
353 void RenderMediaVolumeSliderContainer::layout()
354 {
355     RenderBlock::layout();
356
357     if (style()->display() == NONE || !nextSibling() || !nextSibling()->isBox())
358         return;
359
360     RenderBox* buttonBox = toRenderBox(nextSibling());
361     int absoluteOffsetTop = buttonBox->localToAbsolute(FloatPoint(0, -size().height())).y();
362
363     LayoutStateDisabler layoutStateDisabler(view());
364
365     // If the slider would be rendered outside the page, it should be moved below the controls.
366     if (UNLIKELY(absoluteOffsetTop < 0))
367         setY(buttonBox->offsetTop() + theme()->volumeSliderOffsetFromMuteButton(buttonBox, pixelSnappedSize()).y());
368 }
369
370 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* document)
371     : MediaControlElement(document)
372 {
373 }
374
375 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(Document* document)
376 {
377     RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(document));
378     element->hide();
379     return element.release();
380 }
381
382 RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
383 {
384     return new (arena) RenderMediaVolumeSliderContainer(this);
385 }
386
387 void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
388 {
389     if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
390         return;
391
392     // Poor man's mouseleave event detection.
393     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
394     if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
395         return;
396
397     if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
398         return;
399
400     hide();
401 }
402
403 MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const
404 {
405     return MediaVolumeSliderContainer;
406 }
407
408 const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const
409 {
410     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container"));
411     return id;
412 }
413
414 // ----------------------------
415
416 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document)
417     : MediaControlElement(document)
418     , m_stateBeingDisplayed(Nothing)
419 {
420 }
421
422 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(Document* document)
423 {
424     RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(document));
425     element->hide();
426     return element.release();
427 }
428
429 void MediaControlStatusDisplayElement::update()
430 {
431     // Get the new state that we'll have to display.
432     StateBeingDisplayed newStateToDisplay = Nothing;
433
434     if (mediaController()->readyState() <= MediaControllerInterface::HAVE_METADATA && mediaController()->hasCurrentSrc())
435         newStateToDisplay = Loading;
436     else if (mediaController()->isLiveStream())
437         newStateToDisplay = LiveBroadcast;
438
439     if (newStateToDisplay == m_stateBeingDisplayed)
440         return;
441
442     ExceptionCode e;
443
444     if (m_stateBeingDisplayed == Nothing)
445         show();
446     else if (newStateToDisplay == Nothing)
447         hide();
448
449     m_stateBeingDisplayed = newStateToDisplay;
450
451     switch (m_stateBeingDisplayed) {
452     case Nothing:
453         setInnerText("", e);
454         break;
455     case Loading:
456         setInnerText(mediaElementLoadingStateText(), e);
457         break;
458     case LiveBroadcast:
459         setInnerText(mediaElementLiveBroadcastStateText(), e);
460         break;
461     }
462 }
463
464 MediaControlElementType MediaControlStatusDisplayElement::displayType() const
465 {
466     return MediaStatusDisplay;
467 }
468
469 const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const
470 {
471     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display"));
472     return id;
473 }
474
475 // ----------------------------
476
477 MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType)
478     : HTMLInputElement(inputTag, document, 0, false)
479     , m_mediaController(0)
480     , m_displayType(displayType)
481 {
482 }
483
484 void MediaControlInputElement::show()
485 {
486     removeInlineStyleProperty(CSSPropertyDisplay);
487 }
488
489 void MediaControlInputElement::hide()
490 {
491     setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
492 }
493
494
495 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
496 {
497     if (displayType == m_displayType)
498         return;
499
500     m_displayType = displayType;
501     if (RenderObject* object = renderer())
502         object->repaint();
503 }
504
505 // ----------------------------
506
507 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType)
508     : MediaControlInputElement(document, displayType)
509 {
510 }
511
512 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
513 {
514     if (event->type() == eventNames().clickEvent) {
515         mediaController()->setMuted(!mediaController()->muted());
516         event->setDefaultHandled();
517     }
518
519     HTMLInputElement::defaultEventHandler(event);
520 }
521
522 void MediaControlMuteButtonElement::changedMute()
523 {
524     updateDisplayType();
525 }
526
527 void MediaControlMuteButtonElement::updateDisplayType()
528 {
529     setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton);
530 }
531
532 // ----------------------------
533
534 inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document* document, MediaControls* controls)
535     : MediaControlMuteButtonElement(document, MediaMuteButton)
536     , m_controls(controls)
537 {
538 }
539
540 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document* document, MediaControls* controls)
541 {
542     ASSERT(controls);
543
544     RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
545     button->createShadowSubtree();
546     button->setType("button");
547     return button.release();
548 }
549
550 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
551 {
552     if (event->type() == eventNames().mouseoverEvent)
553         m_controls->showVolumeSlider();
554
555     MediaControlMuteButtonElement::defaultEventHandler(event);
556 }
557
558 const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
559 {
560     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button"));
561     return id;
562 }
563
564 // ----------------------------
565
566 inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document* document)
567     : MediaControlMuteButtonElement(document, MediaMuteButton)
568 {
569 }
570
571 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document* document)
572 {
573     RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
574     button->createShadowSubtree();
575     button->setType("button");
576     return button.release();
577 }
578
579 const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
580 {
581     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button"));
582     return id;
583 }
584
585 // ----------------------------
586
587 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document)
588     : MediaControlInputElement(document, MediaPlayButton)
589 {
590 }
591
592 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document* document)
593 {
594     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
595     button->createShadowSubtree();
596     button->setType("button");
597     return button.release();
598 }
599
600 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
601 {
602     if (event->type() == eventNames().clickEvent) {
603         if (mediaController()->canPlay())
604             mediaController()->play();
605         else
606             mediaController()->pause();
607         updateDisplayType();
608         event->setDefaultHandled();
609     }
610     HTMLInputElement::defaultEventHandler(event);
611 }
612
613 void MediaControlPlayButtonElement::updateDisplayType()
614 {
615     setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
616 }
617
618 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
619 {
620     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button"));
621     return id;
622 }
623
624 // ----------------------------
625
626 inline MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document* document)
627     : MediaControlInputElement(document, MediaOverlayPlayButton)
628 {
629 }
630
631 PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document* document)
632 {
633     RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
634     button->createShadowSubtree();
635     button->setType("button");
636     return button.release();
637 }
638
639 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
640 {
641     if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) {
642         mediaController()->play();
643         updateDisplayType();
644         event->setDefaultHandled();
645     }
646     HTMLInputElement::defaultEventHandler(event);
647 }
648
649 void MediaControlOverlayPlayButtonElement::updateDisplayType()
650 {
651     if (mediaController()->canPlay()) {
652         show();
653         setDisplayType(MediaOverlayPlayButton);
654     } else
655         hide();
656 }
657
658 const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
659 {
660     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button"));
661     return id;
662 }
663
664 // ----------------------------
665
666 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType)
667     : MediaControlInputElement(document, displayType)
668     , m_actionOnStop(Nothing)
669     , m_seekType(Skip)
670     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
671 {
672 }
673
674 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
675 {
676 #if ENABLE(TIZEN_GSTREAMER_VIDEO)
677     if (event->type() == eventNames().clickEvent) {
678         ExceptionCode ignoredCode;
679         float seekTime = isForwardButton() ? cSeekForwardTime : cSeekBackTime;
680         mediaController()->setCurrentTime(mediaController()->currentTime() + seekTime, ignoredCode);
681         event->setDefaultHandled();
682     }
683 #else
684     // Set the mousedown and mouseup events as defaultHandled so they
685     // do not trigger drag start or end actions in MediaControlPanelElement.
686     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
687         event->setDefaultHandled();
688 #endif
689 }
690
691 void MediaControlSeekButtonElement::setActive(bool flag, bool pause)
692 {
693     if (flag == active())
694         return;
695
696     if (flag)
697         startTimer();
698     else
699         stopTimer();
700
701     MediaControlInputElement::setActive(flag, pause);
702 }
703
704 void MediaControlSeekButtonElement::startTimer()
705 {
706     m_seekType = mediaController()->supportsScanning() ? Scan : Skip;
707
708     if (m_seekType == Skip) {
709         // Seeking by skipping requires the video to be paused during seeking.
710         m_actionOnStop = mediaController()->paused() ? Nothing : Play;
711         mediaController()->pause();
712     } else {
713         // Seeking by scanning requires the video to be playing during seeking.
714         m_actionOnStop = mediaController()->paused() ? Pause : Nothing;
715         mediaController()->play();
716         mediaController()->setPlaybackRate(nextRate());
717     }
718
719     m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay);
720 }
721
722 void MediaControlSeekButtonElement::stopTimer()
723 {
724     if (m_seekType == Scan)
725         mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate());
726
727     if (m_actionOnStop == Play)
728         mediaController()->play();
729     else if (m_actionOnStop == Pause)
730         mediaController()->pause();
731
732     if (m_seekTimer.isActive())
733         m_seekTimer.stop();
734 }
735
736 float MediaControlSeekButtonElement::nextRate() const
737 {
738     float rate = std::min(cScanMaximumRate, fabsf(mediaController()->playbackRate() * 2));
739     if (!isForwardButton())
740         rate *= -1;
741     return rate;
742 }
743
744 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
745 {
746     if (m_seekType == Skip) {
747         ExceptionCode ec;
748         float skipTime = isForwardButton() ? cSkipTime : -cSkipTime;
749         mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, ec);
750     } else
751         mediaController()->setPlaybackRate(nextRate());
752 }
753
754 // ----------------------------
755
756 inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(Document* document)
757     : MediaControlSeekButtonElement(document, MediaSeekForwardButton)
758 {
759 }
760
761 PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(Document* document)
762 {
763     RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(document));
764     button->createShadowSubtree();
765     button->setType("button");
766     return button.release();
767 }
768
769 const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const
770 {
771     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button"));
772     return id;
773 }
774
775 // ----------------------------
776
777 inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(Document* document)
778     : MediaControlSeekButtonElement(document, MediaSeekBackButton)
779 {
780 }
781
782 PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(Document* document)
783 {
784     RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(document));
785     button->createShadowSubtree();
786     button->setType("button");
787     return button.release();
788 }
789
790 const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const
791 {
792     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button"));
793     return id;
794 }
795
796 // ----------------------------
797
798 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document)
799     : MediaControlInputElement(document, MediaRewindButton)
800 {
801 }
802
803 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(Document* document)
804 {
805     RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(document));
806     button->createShadowSubtree();
807     button->setType("button");
808     return button.release();
809 }
810
811 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
812 {
813     if (event->type() == eventNames().clickEvent) {
814         ExceptionCode ignoredCode;
815         mediaController()->setCurrentTime(max(0.0f, mediaController()->currentTime() - 30), ignoredCode);
816         event->setDefaultHandled();
817     }
818     HTMLInputElement::defaultEventHandler(event);
819 }
820
821 const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
822 {
823     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button"));
824     return id;
825 }
826
827 // ----------------------------
828
829 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document)
830     : MediaControlInputElement(document, MediaReturnToRealtimeButton)
831 {
832 }
833
834 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(Document* document)
835 {
836     RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(document));
837     button->createShadowSubtree();
838     button->setType("button");
839     button->hide();
840     return button.release();
841 }
842
843 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
844 {
845     if (event->type() == eventNames().clickEvent) {
846         mediaController()->returnToRealtime();
847         event->setDefaultHandled();
848     }
849     HTMLInputElement::defaultEventHandler(event);
850 }
851
852 const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
853 {
854     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button"));
855     return id;
856 }
857
858 // ----------------------------
859
860 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document)
861     : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
862 {
863 }
864
865 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document)
866 {
867     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document));
868     button->createShadowSubtree();
869     button->setType("button");
870     button->hide();
871     return button.release();
872 }
873
874 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
875 {
876     if (event->type() == eventNames().clickEvent) {
877         mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
878         setChecked(mediaController()->closedCaptionsVisible());
879         updateDisplayType();
880         event->setDefaultHandled();
881     }
882
883     HTMLInputElement::defaultEventHandler(event);
884 }
885
886 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
887 {
888     setDisplayType(mediaController()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
889 }
890
891 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
892 {
893     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button"));
894     return id;
895 }
896
897 // ----------------------------
898
899 MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls)
900     : MediaControlInputElement(document, MediaSlider)
901     , m_controls(controls)
902 {
903 }
904
905 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document* document, MediaControls* controls)
906 {
907     ASSERT(controls);
908
909     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
910     timeline->createShadowSubtree();
911     timeline->setType("range");
912     timeline->setAttribute(precisionAttr, "float");
913     return timeline.release();
914 }
915
916 void MediaControlTimelineElement::defaultEventHandler(Event* event)
917 {
918     // Left button is 0. Rejects mouse events not from left button.
919     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
920         return;
921
922     if (!attached())
923         return;
924
925     if (event->type() == eventNames().mousedownEvent)
926         mediaController()->beginScrubbing();
927
928     if (event->type() == eventNames().mouseupEvent)
929         mediaController()->endScrubbing();
930
931     MediaControlInputElement::defaultEventHandler(event);
932
933     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
934         return;
935
936     float time = narrowPrecisionToFloat(value().toDouble());
937     if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) {
938         ExceptionCode ec;
939         mediaController()->setCurrentTime(time, ec);
940     }
941
942     RenderSlider* slider = toRenderSlider(renderer());
943     if (slider && slider->inDragMode())
944         m_controls->updateTimeDisplay();
945 }
946
947 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
948 {
949     if (!attached())
950         return false;
951
952     return true;
953 }
954
955 void MediaControlTimelineElement::setPosition(float currentTime)
956 {
957     setValue(String::number(currentTime));
958 }
959
960 void MediaControlTimelineElement::setDuration(float duration)
961 {
962     setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
963 }
964
965
966 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
967 {
968     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline"));
969     return id;
970 }
971
972 // ----------------------------
973
974 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
975     : MediaControlInputElement(document, MediaVolumeSlider)
976     , m_clearMutedOnUserInteraction(false)
977 {
978 }
979
980 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(Document* document)
981 {
982     RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(document));
983     slider->createShadowSubtree();
984     slider->setType("range");
985     slider->setAttribute(precisionAttr, "float");
986     slider->setAttribute(maxAttr, "1");
987     return slider.release();
988 }
989
990 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
991 {
992     // Left button is 0. Rejects mouse events not from left button.
993     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
994         return;
995
996     if (!attached())
997         return;
998
999     MediaControlInputElement::defaultEventHandler(event);
1000
1001     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
1002         return;
1003
1004     float volume = narrowPrecisionToFloat(value().toDouble());
1005     if (volume != mediaController()->volume()) {
1006         ExceptionCode ec = 0;
1007         mediaController()->setVolume(volume, ec);
1008         ASSERT(!ec);
1009     }
1010     if (m_clearMutedOnUserInteraction)
1011         mediaController()->setMuted(false);
1012 }
1013
1014 bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
1015 {
1016     if (!attached())
1017         return false;
1018
1019     return MediaControlInputElement::willRespondToMouseMoveEvents();
1020 }
1021
1022 bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
1023 {
1024     if (!attached())
1025         return false;
1026
1027     return MediaControlInputElement::willRespondToMouseClickEvents();
1028 }
1029
1030 void MediaControlVolumeSliderElement::setVolume(float volume)
1031 {
1032     if (value().toFloat() != volume)
1033         setValue(String::number(volume));
1034 }
1035
1036 void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
1037 {
1038     m_clearMutedOnUserInteraction = clearMute;
1039 }
1040
1041 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
1042 {
1043     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider"));
1044     return id;
1045 }
1046
1047 // ----------------------------
1048
1049 inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(Document* document)
1050     : MediaControlVolumeSliderElement(document)
1051 {
1052 }
1053
1054 PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(Document* document)
1055 {
1056     RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(document));
1057     slider->createShadowSubtree();
1058     slider->setType("range");
1059     slider->setAttribute(precisionAttr, "float");
1060     slider->setAttribute(maxAttr, "1");
1061     return slider.release();
1062 }
1063
1064 const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
1065 {
1066     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider"));
1067     return id;
1068 }
1069
1070 // ----------------------------
1071
1072 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, MediaControls*)
1073     : MediaControlInputElement(document, MediaEnterFullscreenButton)
1074 {
1075 }
1076
1077 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document* document, MediaControls* controls)
1078 {
1079     ASSERT(controls);
1080
1081     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document, controls));
1082     button->createShadowSubtree();
1083     button->setType("button");
1084     button->hide();
1085     return button.release();
1086 }
1087
1088 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
1089 {
1090     if (event->type() == eventNames().clickEvent) {
1091 #if ENABLE(FULLSCREEN_API)
1092         // Only use the new full screen API if the fullScreenEnabled setting has
1093         // been explicitly enabled. Otherwise, use the old fullscreen API. This
1094         // allows apps which embed a WebView to retain the existing full screen
1095         // video implementation without requiring them to implement their own full
1096         // screen behavior.
1097         if (document()->settings() && document()->settings()->fullScreenEnabled()) {
1098             if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this))
1099                 document()->webkitCancelFullScreen();
1100             else {
1101 #if ENABLE(TIZEN_FULLSCREEN_API)
1102                 document()->requestFullScreenForElement(toParentMediaElement(this), Element::HARDWARE_BACKKEY_EXIT, Document::ExemptIFrameAllowFullScreenRequirement);
1103 #else
1104                 document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
1105 #endif
1106             }
1107         } else
1108 #endif
1109             mediaController()->enterFullscreen();
1110         event->setDefaultHandled();
1111     }
1112     HTMLInputElement::defaultEventHandler(event);
1113 }
1114
1115 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
1116 {
1117     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button"));
1118     return id;
1119 }
1120
1121 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
1122 {
1123     setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
1124 }
1125
1126 // ----------------------------
1127
1128 inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(Document* document)
1129     : MediaControlInputElement(document, MediaUnMuteButton)
1130 {
1131 }
1132
1133 PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(Document* document)
1134 {
1135     RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(document));
1136     button->createShadowSubtree();
1137     button->setType("button");
1138     return button.release();
1139 }
1140
1141 void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
1142 {
1143     if (event->type() == eventNames().clickEvent) {
1144         ExceptionCode code = 0;
1145         mediaController()->setVolume(0, code);
1146         event->setDefaultHandled();
1147     }
1148     HTMLInputElement::defaultEventHandler(event);
1149 }
1150
1151 const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
1152 {
1153     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button"));
1154     return id;
1155 }
1156
1157 // ----------------------------
1158
1159 inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(Document* document)
1160 : MediaControlInputElement(document, MediaMuteButton)
1161 {
1162 }
1163
1164 PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(Document* document)
1165 {
1166     RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(document));
1167     button->createShadowSubtree();
1168     button->setType("button");
1169     return button.release();
1170 }
1171
1172 void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
1173 {
1174     if (event->type() == eventNames().clickEvent) {
1175         ExceptionCode code = 0;
1176         mediaController()->setVolume(1, code);
1177         event->setDefaultHandled();
1178     }
1179     HTMLInputElement::defaultEventHandler(event);
1180 }
1181
1182 const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
1183 {
1184     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button"));
1185     return id;
1186 }
1187
1188 // ----------------------------
1189
1190 class RenderMediaControlTimeDisplay : public RenderDeprecatedFlexibleBox {
1191 public:
1192     RenderMediaControlTimeDisplay(Node*);
1193
1194 private:
1195     virtual void layout();
1196 };
1197
1198 RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
1199     : RenderDeprecatedFlexibleBox(node)
1200 {
1201 }
1202
1203 // We want the timeline slider to be at least 100 pixels wide.
1204 // FIXME: Eliminate hard-coded widths altogether.
1205 static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
1206
1207 void RenderMediaControlTimeDisplay::layout()
1208 {
1209     RenderDeprecatedFlexibleBox::layout();
1210     RenderBox* timelineContainerBox = parentBox();
1211     while (timelineContainerBox && timelineContainerBox->isAnonymous())
1212         timelineContainerBox = timelineContainerBox->parentBox();
1213
1214     if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
1215         setWidth(0);
1216 }
1217
1218 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document)
1219     : MediaControlElement(document)
1220     , m_currentValue(0)
1221 {
1222 }
1223
1224 void MediaControlTimeDisplayElement::setCurrentValue(float time)
1225 {
1226     m_currentValue = time;
1227 }
1228
1229 RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
1230 {
1231     return new (arena) RenderMediaControlTimeDisplay(this);
1232 }
1233
1234 // ----------------------------
1235
1236 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document* document)
1237 {
1238     return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
1239 }
1240
1241 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document* document)
1242     : MediaControlTimeDisplayElement(document)
1243 {
1244 }
1245
1246 MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const
1247 {
1248     return MediaTimeRemainingDisplay;
1249 }
1250
1251 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
1252 {
1253     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display"));
1254     return id;
1255 }
1256
1257 // ----------------------------
1258
1259 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document* document)
1260 {
1261     return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
1262 }
1263
1264 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document* document)
1265     : MediaControlTimeDisplayElement(document)
1266 {
1267 }
1268
1269 MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const
1270 {
1271     return MediaCurrentTimeDisplay;
1272 }
1273
1274 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
1275 {
1276     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display"));
1277     return id;
1278 }
1279
1280 // ----------------------------
1281
1282 #if ENABLE(VIDEO_TRACK)
1283
1284 class RenderTextTrackContainerElement : public RenderBlock {
1285 public:
1286     RenderTextTrackContainerElement(Node*);
1287
1288 private:
1289     virtual void layout();
1290 };
1291
1292 RenderTextTrackContainerElement::RenderTextTrackContainerElement(Node* node)
1293     : RenderBlock(node)
1294 {
1295 }
1296
1297 void RenderTextTrackContainerElement::layout()
1298 {
1299     RenderBlock::layout();
1300     if (style()->display() == NONE)
1301         return;
1302
1303     ASSERT(mediaControlElementType(node()) == MediaTextTrackDisplayContainer);
1304
1305     LayoutStateDisabler layoutStateDisabler(view());
1306     static_cast<MediaControlTextTrackContainerElement*>(node())->updateSizes();
1307 }
1308
1309 inline MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document* document)
1310     : MediaControlElement(document)
1311     , m_fontSize(0)
1312 {
1313 }
1314
1315 PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document* document)
1316 {
1317     RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
1318     element->hide();
1319     return element.release();
1320 }
1321
1322 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
1323 {
1324     return new (arena) RenderTextTrackContainerElement(this);
1325 }
1326
1327 const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
1328 {
1329     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container"));
1330     return id;
1331 }
1332
1333 void MediaControlTextTrackContainerElement::updateDisplay()
1334 {
1335     HTMLMediaElement* mediaElement = toParentMediaElement(this);
1336
1337     // 1. If the media element is an audio element, or is another playback
1338     // mechanism with no rendering area, abort these steps. There is nothing to
1339     // render.
1340     if (!mediaElement->isVideo())
1341         return;
1342
1343     // 2. Let video be the media element or other playback mechanism.
1344     HTMLVideoElement* video = static_cast<HTMLVideoElement*>(mediaElement);
1345
1346     // 3. Let output be an empty list of absolutely positioned CSS block boxes.
1347     Vector<RefPtr<HTMLDivElement> > output;
1348
1349     // 4. If the user agent is exposing a user interface for video, add to
1350     // output one or more completely transparent positioned CSS block boxes that
1351     // cover the same region as the user interface.
1352
1353     // 5. If the last time these rules were run, the user agent was not exposing
1354     // a user interface for video, but now it is, let reset be true. Otherwise,
1355     // let reset be false.
1356
1357     // There is nothing to be done explicitly for 4th and 5th steps, as
1358     // everything is handled through CSS. The caption box is on top of the
1359     // controls box, in a container set with the -webkit-box display property.
1360
1361     // 6. Let tracks be the subset of video's list of text tracks that have as
1362     // their rules for updating the text track rendering these rules for
1363     // updating the display of WebVTT text tracks, and whose text track mode is
1364     // showing or showing by default.
1365     // 7. Let cues be an empty list of text track cues.
1366     // 8. For each track track in tracks, append to cues all the cues from
1367     // track's list of cues that have their text track cue active flag set.
1368     CueList activeCues = video->currentlyActiveCues();
1369
1370     // 9. If reset is false, then, for each text track cue cue in cues: if cue's
1371     // text track cue display state has a set of CSS boxes, then add those boxes
1372     // to output, and remove cue from cues.
1373
1374     // There is nothing explicitly to be done here, as all the caching occurs
1375     // within the TextTrackCue instance itself. If parameters of the cue change,
1376     // the display tree is cleared.
1377
1378     // 10. For each text track cue cue in cues that has not yet had
1379     // corresponding CSS boxes added to output, in text track cue order, run the
1380     // following substeps:
1381     for (size_t i = 0; i < activeCues.size(); ++i) {
1382         TextTrackCue* cue = activeCues[i].data();
1383
1384         ASSERT(cue->isActive());
1385         if (!cue->track() || !cue->track()->isRendered())
1386             continue;
1387
1388         RefPtr<TextTrackCueBox> displayBox = cue->getDisplayTree();
1389
1390         if (displayBox->hasChildNodes() && !contains(static_cast<Node*>(displayBox.get())))
1391             // Note: the display tree of a cue is removed when the active flag of the cue is unset.
1392             appendChild(displayBox, ASSERT_NO_EXCEPTION, false);
1393     }
1394
1395     // 11. Return output.
1396     hasChildNodes() ? show() : hide();
1397 }
1398
1399 static const float mimimumFontSize = 16;
1400 static const float videoHeightFontSizePercentage = .05;
1401 static const float trackBottomMultiplier = .9;
1402
1403 void MediaControlTextTrackContainerElement::updateSizes()
1404 {
1405     HTMLMediaElement* mediaElement = toParentMediaElement(this);
1406     if (!mediaElement || !mediaElement->renderer() || !mediaElement->renderer()->isVideo())
1407         return;
1408
1409     IntRect videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
1410     if (m_videoDisplaySize == videoBox)
1411         return;
1412     m_videoDisplaySize = videoBox;
1413
1414     float fontSize = m_videoDisplaySize.size().height() * videoHeightFontSizePercentage;
1415     if (fontSize != m_fontSize) {
1416         m_fontSize = fontSize;
1417         setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px");
1418     }
1419 }
1420
1421 #endif // ENABLE(VIDEO_TRACK)
1422
1423 // ----------------------------
1424
1425 } // namespace WebCore
1426
1427 #endif // ENABLE(VIDEO)