Upstream version 8.37.180.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/v8/ExceptionStatePlaceholder.h"
34 #include "core/dom/DOMTokenList.h"
35 #include "core/dom/FullscreenElementStack.h"
36 #include "core/dom/shadow/ShadowRoot.h"
37 #include "core/events/MouseEvent.h"
38 #include "core/frame/LocalFrame.h"
39 #include "core/html/HTMLVideoElement.h"
40 #include "core/html/MediaController.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 WebCore {
52
53 using namespace HTMLNames;
54
55 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
56 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
57
58 // If you change any of the following fade durations, then also update the
59 // corresponding values in LayoutTests/media/media-controls.js.
60 static const double fadeInDuration = 0.1;
61 static const double fadeOutDuration = 0.3;
62
63 MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
64     : MediaControlDivElement(mediaControls, MediaControlsPanel)
65     , m_isDisplayed(false)
66     , m_opaque(true)
67     , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
68 {
69 }
70
71 PassRefPtrWillBeRawPtr<MediaControlPanelElement> MediaControlPanelElement::create(MediaControls& mediaControls)
72 {
73     return adoptRefWillBeNoop(new MediaControlPanelElement(mediaControls));
74 }
75
76 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
77 {
78     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
79     return id;
80 }
81
82 void MediaControlPanelElement::defaultEventHandler(Event* event)
83 {
84     // Suppress the media element activation behavior (toggle play/pause) when
85     // any part of the control panel is clicked.
86     if (event->type() == EventTypeNames::click) {
87         event->setDefaultHandled();
88         return;
89     }
90     HTMLDivElement::defaultEventHandler(event);
91 }
92
93 void MediaControlPanelElement::startTimer()
94 {
95     stopTimer();
96
97     // The timer is required to set the property display:'none' on the panel,
98     // such that captions are correctly displayed at the bottom of the video
99     // at the end of the fadeout transition.
100     // FIXME: Racing a transition with a setTimeout like this is wrong.
101     m_transitionTimer.startOneShot(fadeOutDuration, FROM_HERE);
102 }
103
104 void MediaControlPanelElement::stopTimer()
105 {
106     if (m_transitionTimer.isActive())
107         m_transitionTimer.stop();
108 }
109
110 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
111 {
112     if (!m_opaque)
113         hide();
114
115     stopTimer();
116 }
117
118 void MediaControlPanelElement::makeOpaque()
119 {
120     if (m_opaque)
121         return;
122
123     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
124     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeInDuration, CSSPrimitiveValue::CSS_S);
125     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
126
127     m_opaque = true;
128
129     if (m_isDisplayed)
130         show();
131 }
132
133 void MediaControlPanelElement::makeTransparent()
134 {
135     if (!m_opaque)
136         return;
137
138     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
139     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeOutDuration, CSSPrimitiveValue::CSS_S);
140     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
141
142     m_opaque = false;
143     startTimer();
144 }
145
146 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
147 {
148     m_isDisplayed = isDisplayed;
149 }
150
151 // ----------------------------
152
153 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(MediaControls& mediaControls)
154     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
155     : MediaControlDivElement(mediaControls, MediaControlsPanel)
156 {
157 }
158
159 PassRefPtrWillBeRawPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(MediaControls& mediaControls)
160 {
161     return adoptRefWillBeNoop(new MediaControlPanelEnclosureElement(mediaControls));
162 }
163
164 const AtomicString& MediaControlPanelEnclosureElement::shadowPseudoId() const
165 {
166     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
167     return id;
168 }
169
170 // ----------------------------
171
172 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(MediaControls& mediaControls)
173     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
174     : MediaControlDivElement(mediaControls, MediaControlsPanel)
175 {
176 }
177
178 PassRefPtrWillBeRawPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(MediaControls& mediaControls)
179 {
180     return adoptRefWillBeNoop(new MediaControlOverlayEnclosureElement(mediaControls));
181 }
182
183 const AtomicString& MediaControlOverlayEnclosureElement::shadowPseudoId() const
184 {
185     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
186     return id;
187 }
188
189 // ----------------------------
190
191 MediaControlMuteButtonElement::MediaControlMuteButtonElement(MediaControls& mediaControls)
192     : MediaControlInputElement(mediaControls, MediaMuteButton)
193 {
194 }
195
196 PassRefPtrWillBeRawPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(MediaControls& mediaControls)
197 {
198     RefPtrWillBeRawPtr<MediaControlMuteButtonElement> button = adoptRefWillBeNoop(new MediaControlMuteButtonElement(mediaControls));
199     button->ensureUserAgentShadowRoot();
200     button->setType("button");
201     return button.release();
202 }
203
204 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
205 {
206     if (event->type() == EventTypeNames::click) {
207         mediaElement().setMuted(!mediaElement().muted());
208         event->setDefaultHandled();
209     }
210
211     HTMLInputElement::defaultEventHandler(event);
212 }
213
214 void MediaControlMuteButtonElement::updateDisplayType()
215 {
216     setDisplayType(mediaElement().muted() ? MediaUnMuteButton : MediaMuteButton);
217 }
218
219 const AtomicString& MediaControlMuteButtonElement::shadowPseudoId() const
220 {
221     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
222     return id;
223 }
224
225 // ----------------------------
226
227 MediaControlPlayButtonElement::MediaControlPlayButtonElement(MediaControls& mediaControls)
228     : MediaControlInputElement(mediaControls, MediaPlayButton)
229 {
230 }
231
232 PassRefPtrWillBeRawPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(MediaControls& mediaControls)
233 {
234     RefPtrWillBeRawPtr<MediaControlPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlPlayButtonElement(mediaControls));
235     button->ensureUserAgentShadowRoot();
236     button->setType("button");
237     return button.release();
238 }
239
240 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
241 {
242     if (event->type() == EventTypeNames::click) {
243         mediaElement().togglePlayState();
244         updateDisplayType();
245         event->setDefaultHandled();
246     }
247     HTMLInputElement::defaultEventHandler(event);
248 }
249
250 void MediaControlPlayButtonElement::updateDisplayType()
251 {
252     setDisplayType(mediaElement().togglePlayStateWillPlay() ? MediaPlayButton : MediaPauseButton);
253 }
254
255 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
256 {
257     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
258     return id;
259 }
260
261 // ----------------------------
262
263 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(MediaControls& mediaControls)
264     : MediaControlInputElement(mediaControls, MediaOverlayPlayButton)
265 {
266 }
267
268 PassRefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(MediaControls& mediaControls)
269 {
270     RefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlOverlayPlayButtonElement(mediaControls));
271     button->ensureUserAgentShadowRoot();
272     button->setType("button");
273     return button.release();
274 }
275
276 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
277 {
278     if (event->type() == EventTypeNames::click && mediaElement().togglePlayStateWillPlay()) {
279         mediaElement().togglePlayState();
280         updateDisplayType();
281         event->setDefaultHandled();
282     }
283 }
284
285 void MediaControlOverlayPlayButtonElement::updateDisplayType()
286 {
287     if (mediaElement().togglePlayStateWillPlay()) {
288         show();
289     } else
290         hide();
291 }
292
293 const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
294 {
295     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
296     return id;
297 }
298
299
300 // ----------------------------
301
302 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(MediaControls& mediaControls)
303     : MediaControlInputElement(mediaControls, MediaShowClosedCaptionsButton)
304 {
305 }
306
307 PassRefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(MediaControls& mediaControls)
308 {
309     RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRefWillBeNoop(new MediaControlToggleClosedCaptionsButtonElement(mediaControls));
310     button->ensureUserAgentShadowRoot();
311     button->setType("button");
312     button->hide();
313     return button.release();
314 }
315
316 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
317 {
318     bool captionsVisible = mediaElement().closedCaptionsVisible();
319     setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
320     setChecked(captionsVisible);
321 }
322
323 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
324 {
325     if (event->type() == EventTypeNames::click) {
326         mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVisible());
327         setChecked(mediaElement().closedCaptionsVisible());
328         updateDisplayType();
329         event->setDefaultHandled();
330     }
331
332     HTMLInputElement::defaultEventHandler(event);
333 }
334
335 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
336 {
337     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
338     return id;
339 }
340
341 // ----------------------------
342
343 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
344     : MediaControlInputElement(mediaControls, MediaSlider)
345 {
346 }
347
348 PassRefPtrWillBeRawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaControls& mediaControls)
349 {
350     RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = adoptRefWillBeNoop(new MediaControlTimelineElement(mediaControls));
351     timeline->ensureUserAgentShadowRoot();
352     timeline->setType("range");
353     timeline->setAttribute(stepAttr, "any");
354     return timeline.release();
355 }
356
357 void MediaControlTimelineElement::defaultEventHandler(Event* event)
358 {
359     if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
360         return;
361
362     if (!inDocument() || !document().isActive())
363         return;
364
365     if (event->type() == EventTypeNames::mousedown)
366         mediaControls().beginScrubbing();
367
368     if (event->type() == EventTypeNames::mouseup)
369         mediaControls().endScrubbing();
370
371     MediaControlInputElement::defaultEventHandler(event);
372
373     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
374         return;
375
376     double time = value().toDouble();
377     if (event->type() == EventTypeNames::input) {
378         // FIXME: This will need to take the timeline offset into consideration
379         // once that concept is supported, see https://crbug.com/312699
380         if (mediaElement().controller())
381             mediaElement().controller()->setCurrentTime(time, IGNORE_EXCEPTION);
382         else
383             mediaElement().setCurrentTime(time, IGNORE_EXCEPTION);
384     }
385
386     RenderSlider* slider = toRenderSlider(renderer());
387     if (slider && slider->inDragMode())
388         mediaControls().updateCurrentTimeDisplay();
389 }
390
391 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
392 {
393     return inDocument() && document().isActive();
394 }
395
396 void MediaControlTimelineElement::setPosition(double currentTime)
397 {
398     setValue(String::number(currentTime));
399 }
400
401 void MediaControlTimelineElement::setDuration(double duration)
402 {
403     setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0);
404 }
405
406
407 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
408 {
409     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
410     return id;
411 }
412
413 // ----------------------------
414
415 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(MediaControls& mediaControls)
416     : MediaControlInputElement(mediaControls, MediaVolumeSlider)
417 {
418 }
419
420 PassRefPtrWillBeRawPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(MediaControls& mediaControls)
421 {
422     RefPtrWillBeRawPtr<MediaControlVolumeSliderElement> slider = adoptRefWillBeNoop(new MediaControlVolumeSliderElement(mediaControls));
423     slider->ensureUserAgentShadowRoot();
424     slider->setType("range");
425     slider->setAttribute(stepAttr, "any");
426     slider->setAttribute(maxAttr, "1");
427     return slider.release();
428 }
429
430 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
431 {
432     if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
433         return;
434
435     if (!inDocument() || !document().isActive())
436         return;
437
438     MediaControlInputElement::defaultEventHandler(event);
439
440     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
441         return;
442
443     double volume = value().toDouble();
444     mediaElement().setVolume(volume, ASSERT_NO_EXCEPTION);
445     mediaElement().setMuted(false);
446 }
447
448 bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
449 {
450     if (!inDocument() || !document().isActive())
451         return false;
452
453     return MediaControlInputElement::willRespondToMouseMoveEvents();
454 }
455
456 bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
457 {
458     if (!inDocument() || !document().isActive())
459         return false;
460
461     return MediaControlInputElement::willRespondToMouseClickEvents();
462 }
463
464 void MediaControlVolumeSliderElement::setVolume(double volume)
465 {
466     if (value().toDouble() != volume)
467         setValue(String::number(volume));
468 }
469
470 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
471 {
472     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
473     return id;
474 }
475
476 // ----------------------------
477
478 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(MediaControls& mediaControls)
479     : MediaControlInputElement(mediaControls, MediaEnterFullscreenButton)
480 {
481 }
482
483 PassRefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(MediaControls& mediaControls)
484 {
485     RefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> button = adoptRefWillBeNoop(new MediaControlFullscreenButtonElement(mediaControls));
486     button->ensureUserAgentShadowRoot();
487     button->setType("button");
488     button->hide();
489     return button.release();
490 }
491
492 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
493 {
494     if (event->type() == EventTypeNames::click) {
495         if (FullscreenElementStack::isActiveFullScreenElement(&mediaElement()))
496             FullscreenElementStack::from(document()).webkitCancelFullScreen();
497         else
498             FullscreenElementStack::from(document()).requestFullScreenForElement(&mediaElement(), 0, FullscreenElementStack::ExemptIFrameAllowFullScreenRequirement);
499         event->setDefaultHandled();
500     }
501     HTMLInputElement::defaultEventHandler(event);
502 }
503
504 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
505 {
506     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
507     return id;
508 }
509
510 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
511 {
512     setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
513 }
514
515 // ----------------------------
516
517 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(MediaControls& mediaControls)
518     : MediaControlTimeDisplayElement(mediaControls, MediaTimeRemainingDisplay)
519 {
520 }
521
522 PassRefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(MediaControls& mediaControls)
523 {
524     return adoptRefWillBeNoop(new MediaControlTimeRemainingDisplayElement(mediaControls));
525 }
526
527 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
528 {
529     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
530     return id;
531 }
532
533 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
534 {
535     return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
536 }
537
538 // ----------------------------
539
540 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(MediaControls& mediaControls)
541     : MediaControlTimeDisplayElement(mediaControls, MediaCurrentTimeDisplay)
542 {
543 }
544
545 PassRefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(MediaControls& mediaControls)
546 {
547     return adoptRefWillBeNoop(new MediaControlCurrentTimeDisplayElement(mediaControls));
548 }
549
550 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
551 {
552     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
553     return id;
554 }
555
556 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
557 {
558     return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
559 }
560
561 // ----------------------------
562
563 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(MediaControls& mediaControls)
564     : MediaControlDivElement(mediaControls, MediaTextTrackDisplayContainer)
565     , m_fontSize(0)
566 {
567 }
568
569 PassRefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(MediaControls& mediaControls)
570 {
571     RefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> element = adoptRefWillBeNoop(new MediaControlTextTrackContainerElement(mediaControls));
572     element->hide();
573     return element.release();
574 }
575
576 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*)
577 {
578     return new RenderTextTrackContainerElement(this);
579 }
580
581 const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
582 {
583     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
584     return id;
585 }
586
587 const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
588 {
589     return textTrackContainerElementShadowPseudoId();
590 }
591
592 void MediaControlTextTrackContainerElement::updateDisplay()
593 {
594     if (!mediaElement().closedCaptionsVisible()) {
595         removeChildren();
596         return;
597     }
598
599     // 1. If the media element is an audio element, or is another playback
600     // mechanism with no rendering area, abort these steps. There is nothing to
601     // render.
602     if (isHTMLAudioElement(mediaElement()))
603         return;
604
605     // 2. Let video be the media element or other playback mechanism.
606     HTMLVideoElement& video = toHTMLVideoElement(mediaElement());
607
608     // 3. Let output be an empty list of absolutely positioned CSS block boxes.
609
610     // 4. If the user agent is exposing a user interface for video, add to
611     // output one or more completely transparent positioned CSS block boxes that
612     // cover the same region as the user interface.
613
614     // 5. If the last time these rules were run, the user agent was not exposing
615     // a user interface for video, but now it is, let reset be true. Otherwise,
616     // let reset be false.
617
618     // There is nothing to be done explicitly for 4th and 5th steps, as
619     // everything is handled through CSS. The caption box is on top of the
620     // controls box, in a container set with the -webkit-box display property.
621
622     // 6. Let tracks be the subset of video's list of text tracks that have as
623     // their rules for updating the text track rendering these rules for
624     // updating the display of WebVTT text tracks, and whose text track mode is
625     // showing or showing by default.
626     // 7. Let cues be an empty list of text track cues.
627     // 8. For each track track in tracks, append to cues all the cues from
628     // track's list of cues that have their text track cue active flag set.
629     CueList activeCues = video.currentlyActiveCues();
630
631     // 9. If reset is false, then, for each text track cue cue in cues: if cue's
632     // text track cue display state has a set of CSS boxes, then add those boxes
633     // to output, and remove cue from cues.
634
635     // There is nothing explicitly to be done here, as all the caching occurs
636     // within the TextTrackCue instance itself. If parameters of the cue change,
637     // the display tree is cleared.
638
639     // 10. For each text track cue cue in cues that has not yet had
640     // corresponding CSS boxes added to output, in text track cue order, run the
641     // following substeps:
642     for (size_t i = 0; i < activeCues.size(); ++i) {
643         TextTrackCue* cue = activeCues[i].data();
644
645         ASSERT(cue->isActive());
646         if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
647             continue;
648
649         cue->updateDisplay(m_videoDisplaySize.size(), *this);
650     }
651
652     // 11. Return output.
653     if (hasChildren())
654         show();
655     else
656         hide();
657 }
658
659 void MediaControlTextTrackContainerElement::updateSizes()
660 {
661     if (!document().isActive())
662         return;
663
664     IntRect videoBox;
665
666     if (!mediaElement().renderer() || !mediaElement().renderer()->isVideo())
667         return;
668     videoBox = toRenderVideo(mediaElement().renderer())->videoBox();
669
670     if (m_videoDisplaySize == videoBox)
671         return;
672     m_videoDisplaySize = videoBox;
673
674     float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
675
676     float fontSize = smallestDimension * 0.05f;
677     if (fontSize != m_fontSize) {
678         m_fontSize = fontSize;
679         setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX);
680     }
681 }
682
683 // ----------------------------
684
685 } // namespace WebCore