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