Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / shadow / MediaControlElements.cpp
1 /*
2  * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2012 Google Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "core/html/shadow/MediaControlElements.h"
32
33 #include "bindings/core/v8/ExceptionStatePlaceholder.h"
34 #include "core/dom/DOMTokenList.h"
35 #include "core/dom/shadow/ShadowRoot.h"
36 #include "core/events/MouseEvent.h"
37 #include "core/frame/LocalFrame.h"
38 #include "core/html/HTMLVideoElement.h"
39 #include "core/html/MediaController.h"
40 #include "core/html/TimeRanges.h"
41 #include "core/html/shadow/MediaControls.h"
42 #include "core/html/track/TextTrack.h"
43 #include "core/html/track/vtt/VTTRegionList.h"
44 #include "core/page/EventHandler.h"
45 #include "core/rendering/RenderMediaControlElements.h"
46 #include "core/rendering/RenderSlider.h"
47 #include "core/rendering/RenderTheme.h"
48 #include "core/rendering/RenderVideo.h"
49 #include "platform/RuntimeEnabledFeatures.h"
50
51 namespace blink {
52
53 using namespace HTMLNames;
54
55 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
56 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
57
58 // This is the duration from mediaControls.css
59 static const double fadeOutDuration = 0.3;
60
61 static bool isUserInteractionEvent(Event* event)
62 {
63     const AtomicString& type = event->type();
64     return type == EventTypeNames::mousedown
65         || type == EventTypeNames::mouseup
66         || type == EventTypeNames::click
67         || type == EventTypeNames::dblclick
68         || event->isKeyboardEvent()
69         || event->isTouchEvent();
70 }
71
72 // Sliders (the volume control and timeline) need to capture some additional events used when dragging the thumb.
73 static bool isUserInteractionEventForSlider(Event* event)
74 {
75     const AtomicString& type = event->type();
76     return type == EventTypeNames::mousedown
77         || type == EventTypeNames::mouseup
78         || type == EventTypeNames::click
79         || type == EventTypeNames::dblclick
80         || type == EventTypeNames::mouseover
81         || type == EventTypeNames::mouseout
82         || type == EventTypeNames::mousemove
83         || event->isKeyboardEvent()
84         || event->isTouchEvent();
85 }
86
87
88 MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
89     : MediaControlDivElement(mediaControls, MediaControlsPanel)
90     , m_isDisplayed(false)
91     , m_opaque(true)
92     , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
93 {
94 }
95
96 PassRefPtrWillBeRawPtr<MediaControlPanelElement> MediaControlPanelElement::create(MediaControls& mediaControls)
97 {
98     return adoptRefWillBeNoop(new MediaControlPanelElement(mediaControls));
99 }
100
101 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
102 {
103     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
104     return id;
105 }
106
107 void MediaControlPanelElement::defaultEventHandler(Event* event)
108 {
109     // Suppress the media element activation behavior (toggle play/pause) when
110     // any part of the control panel is clicked.
111     if (event->type() == EventTypeNames::click) {
112         event->setDefaultHandled();
113         return;
114     }
115     HTMLDivElement::defaultEventHandler(event);
116 }
117
118 void MediaControlPanelElement::startTimer()
119 {
120     stopTimer();
121
122     // The timer is required to set the property display:'none' on the panel,
123     // such that captions are correctly displayed at the bottom of the video
124     // at the end of the fadeout transition.
125     // FIXME: Racing a transition with a setTimeout like this is wrong.
126     m_transitionTimer.startOneShot(fadeOutDuration, FROM_HERE);
127 }
128
129 void MediaControlPanelElement::stopTimer()
130 {
131     if (m_transitionTimer.isActive())
132         m_transitionTimer.stop();
133 }
134
135 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
136 {
137     if (!m_opaque)
138         hide();
139
140     stopTimer();
141 }
142
143 void MediaControlPanelElement::makeOpaque()
144 {
145     if (m_opaque)
146         return;
147
148     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
149     m_opaque = true;
150
151     if (m_isDisplayed)
152         show();
153 }
154
155 void MediaControlPanelElement::makeTransparent()
156 {
157     if (!m_opaque)
158         return;
159
160     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
161
162     m_opaque = false;
163     startTimer();
164 }
165
166 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
167 {
168     m_isDisplayed = isDisplayed;
169 }
170
171 bool MediaControlPanelElement::keepEventInNode(Event* event)
172 {
173     return isUserInteractionEvent(event);
174 }
175
176 // ----------------------------
177
178 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(MediaControls& mediaControls)
179     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
180     : MediaControlDivElement(mediaControls, MediaControlsPanel)
181 {
182 }
183
184 PassRefPtrWillBeRawPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(MediaControls& mediaControls)
185 {
186     return adoptRefWillBeNoop(new MediaControlPanelEnclosureElement(mediaControls));
187 }
188
189 const AtomicString& MediaControlPanelEnclosureElement::shadowPseudoId() const
190 {
191     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
192     return id;
193 }
194
195 // ----------------------------
196
197 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(MediaControls& mediaControls)
198     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
199     : MediaControlDivElement(mediaControls, MediaControlsPanel)
200 {
201 }
202
203 PassRefPtrWillBeRawPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(MediaControls& mediaControls)
204 {
205     return adoptRefWillBeNoop(new MediaControlOverlayEnclosureElement(mediaControls));
206 }
207
208 const AtomicString& MediaControlOverlayEnclosureElement::shadowPseudoId() const
209 {
210     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
211     return id;
212 }
213
214 void* MediaControlOverlayEnclosureElement::preDispatchEventHandler(Event* event)
215 {
216     // When the media element is clicked or touched we want to make the overlay cast button visible
217     // (if the other requirements are right) even if JavaScript is doing its own handling of the event.
218     // Doing it in preDispatchEventHandler prevents any interference from JavaScript.
219     // Note that we can't simply test for click, since JS handling of touch events can prevent their translation to click events.
220     if (event && (event->type() == EventTypeNames::click || event->type() == EventTypeNames::touchstart) && mediaElement().hasRemoteRoutes() && !mediaElement().shouldShowControls())
221         mediaControls().showOverlayCastButton();
222     return MediaControlDivElement::preDispatchEventHandler(event);
223 }
224
225
226 // ----------------------------
227
228 MediaControlMuteButtonElement::MediaControlMuteButtonElement(MediaControls& mediaControls)
229     : MediaControlInputElement(mediaControls, MediaMuteButton)
230 {
231 }
232
233 PassRefPtrWillBeRawPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(MediaControls& mediaControls)
234 {
235     RefPtrWillBeRawPtr<MediaControlMuteButtonElement> button = adoptRefWillBeNoop(new MediaControlMuteButtonElement(mediaControls));
236     button->ensureUserAgentShadowRoot();
237     button->setType("button");
238     return button.release();
239 }
240
241 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
242 {
243     if (event->type() == EventTypeNames::click) {
244         mediaElement().setMuted(!mediaElement().muted());
245         event->setDefaultHandled();
246     }
247
248     HTMLInputElement::defaultEventHandler(event);
249 }
250
251 void MediaControlMuteButtonElement::updateDisplayType()
252 {
253     setDisplayType(mediaElement().muted() ? MediaUnMuteButton : MediaMuteButton);
254 }
255
256 const AtomicString& MediaControlMuteButtonElement::shadowPseudoId() const
257 {
258     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
259     return id;
260 }
261
262 // ----------------------------
263
264 MediaControlPlayButtonElement::MediaControlPlayButtonElement(MediaControls& mediaControls)
265     : MediaControlInputElement(mediaControls, MediaPlayButton)
266 {
267 }
268
269 PassRefPtrWillBeRawPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(MediaControls& mediaControls)
270 {
271     RefPtrWillBeRawPtr<MediaControlPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlPlayButtonElement(mediaControls));
272     button->ensureUserAgentShadowRoot();
273     button->setType("button");
274     return button.release();
275 }
276
277 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
278 {
279     if (event->type() == EventTypeNames::click) {
280         mediaElement().togglePlayState();
281         updateDisplayType();
282         event->setDefaultHandled();
283     }
284     HTMLInputElement::defaultEventHandler(event);
285 }
286
287 void MediaControlPlayButtonElement::updateDisplayType()
288 {
289     setDisplayType(mediaElement().togglePlayStateWillPlay() ? MediaPlayButton : MediaPauseButton);
290 }
291
292 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
293 {
294     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
295     return id;
296 }
297
298 // ----------------------------
299
300 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(MediaControls& mediaControls)
301     : MediaControlInputElement(mediaControls, MediaOverlayPlayButton)
302 {
303 }
304
305 PassRefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(MediaControls& mediaControls)
306 {
307     RefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlOverlayPlayButtonElement(mediaControls));
308     button->ensureUserAgentShadowRoot();
309     button->setType("button");
310     return button.release();
311 }
312
313 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
314 {
315     if (event->type() == EventTypeNames::click && mediaElement().togglePlayStateWillPlay()) {
316         mediaElement().togglePlayState();
317         updateDisplayType();
318         event->setDefaultHandled();
319     }
320 }
321
322 void MediaControlOverlayPlayButtonElement::updateDisplayType()
323 {
324     if (mediaElement().shouldShowControls() && mediaElement().togglePlayStateWillPlay())
325         show();
326     else
327         hide();
328 }
329
330 const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
331 {
332     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
333     return id;
334 }
335
336 bool MediaControlOverlayPlayButtonElement::keepEventInNode(Event* event)
337 {
338     return isUserInteractionEvent(event);
339 }
340
341
342 // ----------------------------
343
344 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(MediaControls& mediaControls)
345     : MediaControlInputElement(mediaControls, MediaShowClosedCaptionsButton)
346 {
347 }
348
349 PassRefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(MediaControls& mediaControls)
350 {
351     RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRefWillBeNoop(new MediaControlToggleClosedCaptionsButtonElement(mediaControls));
352     button->ensureUserAgentShadowRoot();
353     button->setType("button");
354     button->hide();
355     return button.release();
356 }
357
358 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
359 {
360     bool captionsVisible = mediaElement().closedCaptionsVisible();
361     setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
362     setChecked(captionsVisible);
363 }
364
365 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
366 {
367     if (event->type() == EventTypeNames::click) {
368         mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVisible());
369         setChecked(mediaElement().closedCaptionsVisible());
370         updateDisplayType();
371         event->setDefaultHandled();
372     }
373
374     HTMLInputElement::defaultEventHandler(event);
375 }
376
377 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
378 {
379     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
380     return id;
381 }
382
383 // ----------------------------
384
385 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
386     : MediaControlInputElement(mediaControls, MediaSlider)
387 {
388 }
389
390 PassRefPtrWillBeRawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaControls& mediaControls)
391 {
392     RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = adoptRefWillBeNoop(new MediaControlTimelineElement(mediaControls));
393     timeline->ensureUserAgentShadowRoot();
394     timeline->setType("range");
395     timeline->setAttribute(stepAttr, "any");
396     return timeline.release();
397 }
398
399 void MediaControlTimelineElement::defaultEventHandler(Event* event)
400 {
401     if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
402         return;
403
404     if (!inDocument() || !document().isActive())
405         return;
406
407     if (event->type() == EventTypeNames::mousedown)
408         mediaControls().beginScrubbing();
409
410     if (event->type() == EventTypeNames::mouseup)
411         mediaControls().endScrubbing();
412
413     MediaControlInputElement::defaultEventHandler(event);
414
415     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
416         return;
417
418     double time = value().toDouble();
419     if (event->type() == EventTypeNames::input) {
420         // FIXME: This will need to take the timeline offset into consideration
421         // once that concept is supported, see https://crbug.com/312699
422         if (mediaElement().controller()) {
423             if (mediaElement().controller()->seekable()->contain(time))
424                 mediaElement().controller()->setCurrentTime(time);
425         } else if (mediaElement().seekable()->contain(time)) {
426             mediaElement().setCurrentTime(time, IGNORE_EXCEPTION);
427         }
428     }
429
430     RenderSlider* slider = toRenderSlider(renderer());
431     if (slider && slider->inDragMode())
432         mediaControls().updateCurrentTimeDisplay();
433 }
434
435 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
436 {
437     return inDocument() && document().isActive();
438 }
439
440 void MediaControlTimelineElement::setPosition(double currentTime)
441 {
442     setValue(String::number(currentTime));
443 }
444
445 void MediaControlTimelineElement::setDuration(double duration)
446 {
447     setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0);
448 }
449
450 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
451 {
452     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
453     return id;
454 }
455
456 bool MediaControlTimelineElement::keepEventInNode(Event* event)
457 {
458     return isUserInteractionEventForSlider(event);
459 }
460
461 // ----------------------------
462
463 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(MediaControls& mediaControls)
464     : MediaControlInputElement(mediaControls, MediaVolumeSlider)
465 {
466 }
467
468 PassRefPtrWillBeRawPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(MediaControls& mediaControls)
469 {
470     RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = adoptRefWillBeNoop(new MediaControlVolumeSliderElement(mediaControls));
471     slider->ensureUserAgentShadowRoot();
472     slider->setType("range");
473     slider->setAttribute(stepAttr, "any");
474     slider->setAttribute(maxAttr, "1");
475     return slider.release();
476 }
477
478 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
479 {
480     if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
481         return;
482
483     if (!inDocument() || !document().isActive())
484         return;
485
486     MediaControlInputElement::defaultEventHandler(event);
487
488     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
489         return;
490
491     double volume = value().toDouble();
492     mediaElement().setVolume(volume, ASSERT_NO_EXCEPTION);
493     mediaElement().setMuted(false);
494 }
495
496 bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
497 {
498     if (!inDocument() || !document().isActive())
499         return false;
500
501     return MediaControlInputElement::willRespondToMouseMoveEvents();
502 }
503
504 bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
505 {
506     if (!inDocument() || !document().isActive())
507         return false;
508
509     return MediaControlInputElement::willRespondToMouseClickEvents();
510 }
511
512 void MediaControlVolumeSliderElement::setVolume(double volume)
513 {
514     if (value().toDouble() != volume)
515         setValue(String::number(volume));
516 }
517
518 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
519 {
520     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
521     return id;
522 }
523
524 bool MediaControlVolumeSliderElement::keepEventInNode(Event* event)
525 {
526     return isUserInteractionEventForSlider(event);
527 }
528
529 // ----------------------------
530
531 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(MediaControls& mediaControls)
532     : MediaControlInputElement(mediaControls, MediaEnterFullscreenButton)
533 {
534 }
535
536 PassRefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(MediaControls& mediaControls)
537 {
538     RefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> button = adoptRefWillBeNoop(new MediaControlFullscreenButtonElement(mediaControls));
539     button->ensureUserAgentShadowRoot();
540     button->setType("button");
541     button->hide();
542     return button.release();
543 }
544
545 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
546 {
547     if (event->type() == EventTypeNames::click) {
548         if (mediaElement().isFullscreen())
549             mediaElement().exitFullscreen();
550         else
551             mediaElement().enterFullscreen();
552         event->setDefaultHandled();
553     }
554     HTMLInputElement::defaultEventHandler(event);
555 }
556
557 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
558 {
559     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
560     return id;
561 }
562
563 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
564 {
565     setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
566 }
567
568 // ----------------------------
569
570 MediaControlCastButtonElement::MediaControlCastButtonElement(MediaControls& mediaControls, bool isOverlayButton)
571     : MediaControlInputElement(mediaControls, MediaCastOnButton), m_isOverlayButton(isOverlayButton)
572 {
573     setIsPlayingRemotely(false);
574 }
575
576 PassRefPtrWillBeRawPtr<MediaControlCastButtonElement> MediaControlCastButtonElement::create(MediaControls& mediaControls, bool isOverlayButton)
577 {
578     RefPtrWillBeRawPtr<MediaControlCastButtonElement> button = adoptRefWillBeNoop(new MediaControlCastButtonElement(mediaControls, isOverlayButton));
579     button->ensureUserAgentShadowRoot();
580     button->setType("button");
581     return button.release();
582 }
583
584 void MediaControlCastButtonElement::defaultEventHandler(Event* event)
585 {
586     if (event->type() == EventTypeNames::click) {
587         if (mediaElement().isPlayingRemotely()) {
588             mediaElement().requestRemotePlaybackControl();
589         } else {
590             mediaElement().requestRemotePlayback();
591         }
592     }
593     HTMLInputElement::defaultEventHandler(event);
594 }
595
596 const AtomicString& MediaControlCastButtonElement::shadowPseudoId() const
597 {
598     DEFINE_STATIC_LOCAL(AtomicString, id_nonOverlay, ("-internal-media-controls-cast-button", AtomicString::ConstructFromLiteral));
599     DEFINE_STATIC_LOCAL(AtomicString, id_overlay, ("-internal-media-controls-overlay-cast-button", AtomicString::ConstructFromLiteral));
600     return m_isOverlayButton ? id_overlay : id_nonOverlay;
601 }
602
603 void MediaControlCastButtonElement::setIsPlayingRemotely(bool isPlayingRemotely)
604 {
605     if (isPlayingRemotely) {
606         if (m_isOverlayButton) {
607             setDisplayType(MediaOverlayCastOnButton);
608         } else {
609             setDisplayType(MediaCastOnButton);
610         }
611     } else {
612         if (m_isOverlayButton) {
613             setDisplayType(MediaOverlayCastOffButton);
614         } else {
615             setDisplayType(MediaCastOffButton);
616         }
617     }
618 }
619
620 bool MediaControlCastButtonElement::keepEventInNode(Event* event)
621 {
622     return isUserInteractionEvent(event);
623 }
624
625 // ----------------------------
626
627 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(MediaControls& mediaControls)
628     : MediaControlTimeDisplayElement(mediaControls, MediaTimeRemainingDisplay)
629 {
630 }
631
632 PassRefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(MediaControls& mediaControls)
633 {
634     return adoptRefWillBeNoop(new MediaControlTimeRemainingDisplayElement(mediaControls));
635 }
636
637 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
638 {
639     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
640     return id;
641 }
642
643 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
644 {
645     return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
646 }
647
648 // ----------------------------
649
650 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(MediaControls& mediaControls)
651     : MediaControlTimeDisplayElement(mediaControls, MediaCurrentTimeDisplay)
652 {
653 }
654
655 PassRefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(MediaControls& mediaControls)
656 {
657     return adoptRefWillBeNoop(new MediaControlCurrentTimeDisplayElement(mediaControls));
658 }
659
660 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
661 {
662     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
663     return id;
664 }
665
666 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
667 {
668     return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
669 }
670
671 // ----------------------------
672
673 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(MediaControls& mediaControls)
674     : MediaControlDivElement(mediaControls, MediaTextTrackDisplayContainer)
675     , m_fontSize(0)
676 {
677 }
678
679 PassRefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(MediaControls& mediaControls)
680 {
681     RefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> element = adoptRefWillBeNoop(new MediaControlTextTrackContainerElement(mediaControls));
682     element->hide();
683     return element.release();
684 }
685
686 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*)
687 {
688     return new RenderTextTrackContainerElement(this);
689 }
690
691 const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
692 {
693     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
694     return id;
695 }
696
697 const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
698 {
699     return textTrackContainerElementShadowPseudoId();
700 }
701
702 void MediaControlTextTrackContainerElement::updateDisplay()
703 {
704     if (!mediaElement().closedCaptionsVisible()) {
705         removeChildren();
706         return;
707     }
708
709     // 1. If the media element is an audio element, or is another playback
710     // mechanism with no rendering area, abort these steps. There is nothing to
711     // render.
712     if (isHTMLAudioElement(mediaElement()))
713         return;
714
715     // 2. Let video be the media element or other playback mechanism.
716     HTMLVideoElement& video = toHTMLVideoElement(mediaElement());
717
718     // 3. Let output be an empty list of absolutely positioned CSS block boxes.
719
720     // 4. If the user agent is exposing a user interface for video, add to
721     // output one or more completely transparent positioned CSS block boxes that
722     // cover the same region as the user interface.
723
724     // 5. If the last time these rules were run, the user agent was not exposing
725     // a user interface for video, but now it is, let reset be true. Otherwise,
726     // let reset be false.
727
728     // There is nothing to be done explicitly for 4th and 5th steps, as
729     // everything is handled through CSS. The caption box is on top of the
730     // controls box, in a container set with the -webkit-box display property.
731
732     // 6. Let tracks be the subset of video's list of text tracks that have as
733     // their rules for updating the text track rendering these rules for
734     // updating the display of WebVTT text tracks, and whose text track mode is
735     // showing or showing by default.
736     // 7. Let cues be an empty list of text track cues.
737     // 8. For each track track in tracks, append to cues all the cues from
738     // track's list of cues that have their text track cue active flag set.
739     CueList activeCues = video.currentlyActiveCues();
740
741     // 9. If reset is false, then, for each text track cue cue in cues: if cue's
742     // text track cue display state has a set of CSS boxes, then add those boxes
743     // to output, and remove cue from cues.
744
745     // There is nothing explicitly to be done here, as all the caching occurs
746     // within the TextTrackCue instance itself. If parameters of the cue change,
747     // the display tree is cleared.
748
749     // 10. For each text track cue cue in cues that has not yet had
750     // corresponding CSS boxes added to output, in text track cue order, run the
751     // following substeps:
752     for (size_t i = 0; i < activeCues.size(); ++i) {
753         TextTrackCue* cue = activeCues[i].data();
754
755         ASSERT(cue->isActive());
756         if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
757             continue;
758
759         cue->updateDisplay(m_videoDisplaySize.size(), *this);
760     }
761
762     // 11. Return output.
763     if (hasChildren())
764         show();
765     else
766         hide();
767 }
768
769 void MediaControlTextTrackContainerElement::updateSizes()
770 {
771     if (!document().isActive())
772         return;
773
774     IntRect videoBox;
775
776     if (!mediaElement().renderer() || !mediaElement().renderer()->isVideo())
777         return;
778     videoBox = toRenderVideo(mediaElement().renderer())->videoBox();
779
780     if (m_videoDisplaySize == videoBox)
781         return;
782     m_videoDisplaySize = videoBox;
783
784     float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
785
786     float fontSize = smallestDimension * 0.05f;
787     if (fontSize != m_fontSize) {
788         m_fontSize = fontSize;
789         setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX);
790     }
791 }
792
793 // ----------------------------
794
795 } // namespace blink