2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3 * Copyright (C) 2012 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "core/html/shadow/MediaControlElements.h"
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"
53 using namespace HTMLNames;
55 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
56 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
58 // This is the duration from mediaControls.css
59 static const double fadeOutDuration = 0.3;
61 static bool isUserInteractionEvent(Event* event)
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();
72 // Sliders (the volume control and timeline) need to capture some additional events used when dragging the thumb.
73 static bool isUserInteractionEventForSlider(Event* event)
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();
88 MediaControlPanelElement::MediaControlPanelElement(MediaControls& mediaControls)
89 : MediaControlDivElement(mediaControls, MediaControlsPanel)
90 , m_isDisplayed(false)
92 , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
96 PassRefPtrWillBeRawPtr<MediaControlPanelElement> MediaControlPanelElement::create(MediaControls& mediaControls)
98 return adoptRefWillBeNoop(new MediaControlPanelElement(mediaControls));
101 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
103 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
107 void MediaControlPanelElement::defaultEventHandler(Event* event)
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();
115 HTMLDivElement::defaultEventHandler(event);
118 void MediaControlPanelElement::startTimer()
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);
129 void MediaControlPanelElement::stopTimer()
131 if (m_transitionTimer.isActive())
132 m_transitionTimer.stop();
135 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
143 void MediaControlPanelElement::makeOpaque()
148 setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
155 void MediaControlPanelElement::makeTransparent()
160 setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
166 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
168 m_isDisplayed = isDisplayed;
171 bool MediaControlPanelElement::keepEventInNode(Event* event)
173 return isUserInteractionEvent(event);
176 // ----------------------------
178 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(MediaControls& mediaControls)
179 // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
180 : MediaControlDivElement(mediaControls, MediaControlsPanel)
184 PassRefPtrWillBeRawPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(MediaControls& mediaControls)
186 return adoptRefWillBeNoop(new MediaControlPanelEnclosureElement(mediaControls));
189 const AtomicString& MediaControlPanelEnclosureElement::shadowPseudoId() const
191 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
195 // ----------------------------
197 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(MediaControls& mediaControls)
198 // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
199 : MediaControlDivElement(mediaControls, MediaControlsPanel)
203 PassRefPtrWillBeRawPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(MediaControls& mediaControls)
205 return adoptRefWillBeNoop(new MediaControlOverlayEnclosureElement(mediaControls));
208 const AtomicString& MediaControlOverlayEnclosureElement::shadowPseudoId() const
210 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
214 void* MediaControlOverlayEnclosureElement::preDispatchEventHandler(Event* event)
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);
226 // ----------------------------
228 MediaControlMuteButtonElement::MediaControlMuteButtonElement(MediaControls& mediaControls)
229 : MediaControlInputElement(mediaControls, MediaMuteButton)
233 PassRefPtrWillBeRawPtr<MediaControlMuteButtonElement> MediaControlMuteButtonElement::create(MediaControls& mediaControls)
235 RefPtrWillBeRawPtr<MediaControlMuteButtonElement> button = adoptRefWillBeNoop(new MediaControlMuteButtonElement(mediaControls));
236 button->ensureUserAgentShadowRoot();
237 button->setType("button");
238 return button.release();
241 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
243 if (event->type() == EventTypeNames::click) {
244 mediaElement().setMuted(!mediaElement().muted());
245 event->setDefaultHandled();
248 HTMLInputElement::defaultEventHandler(event);
251 void MediaControlMuteButtonElement::updateDisplayType()
253 setDisplayType(mediaElement().muted() ? MediaUnMuteButton : MediaMuteButton);
256 const AtomicString& MediaControlMuteButtonElement::shadowPseudoId() const
258 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
262 // ----------------------------
264 MediaControlPlayButtonElement::MediaControlPlayButtonElement(MediaControls& mediaControls)
265 : MediaControlInputElement(mediaControls, MediaPlayButton)
269 PassRefPtrWillBeRawPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(MediaControls& mediaControls)
271 RefPtrWillBeRawPtr<MediaControlPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlPlayButtonElement(mediaControls));
272 button->ensureUserAgentShadowRoot();
273 button->setType("button");
274 return button.release();
277 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
279 if (event->type() == EventTypeNames::click) {
280 mediaElement().togglePlayState();
282 event->setDefaultHandled();
284 HTMLInputElement::defaultEventHandler(event);
287 void MediaControlPlayButtonElement::updateDisplayType()
289 setDisplayType(mediaElement().togglePlayStateWillPlay() ? MediaPlayButton : MediaPauseButton);
292 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
294 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
298 // ----------------------------
300 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(MediaControls& mediaControls)
301 : MediaControlInputElement(mediaControls, MediaOverlayPlayButton)
305 PassRefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(MediaControls& mediaControls)
307 RefPtrWillBeRawPtr<MediaControlOverlayPlayButtonElement> button = adoptRefWillBeNoop(new MediaControlOverlayPlayButtonElement(mediaControls));
308 button->ensureUserAgentShadowRoot();
309 button->setType("button");
310 return button.release();
313 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
315 if (event->type() == EventTypeNames::click && mediaElement().togglePlayStateWillPlay()) {
316 mediaElement().togglePlayState();
318 event->setDefaultHandled();
322 void MediaControlOverlayPlayButtonElement::updateDisplayType()
324 if (mediaElement().shouldShowControls() && mediaElement().togglePlayStateWillPlay())
330 const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
332 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
336 bool MediaControlOverlayPlayButtonElement::keepEventInNode(Event* event)
338 return isUserInteractionEvent(event);
342 // ----------------------------
344 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(MediaControls& mediaControls)
345 : MediaControlInputElement(mediaControls, MediaShowClosedCaptionsButton)
349 PassRefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(MediaControls& mediaControls)
351 RefPtrWillBeRawPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRefWillBeNoop(new MediaControlToggleClosedCaptionsButtonElement(mediaControls));
352 button->ensureUserAgentShadowRoot();
353 button->setType("button");
355 return button.release();
358 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
360 bool captionsVisible = mediaElement().closedCaptionsVisible();
361 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
362 setChecked(captionsVisible);
365 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
367 if (event->type() == EventTypeNames::click) {
368 mediaElement().setClosedCaptionsVisible(!mediaElement().closedCaptionsVisible());
369 setChecked(mediaElement().closedCaptionsVisible());
371 event->setDefaultHandled();
374 HTMLInputElement::defaultEventHandler(event);
377 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
379 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
383 // ----------------------------
385 MediaControlTimelineElement::MediaControlTimelineElement(MediaControls& mediaControls)
386 : MediaControlInputElement(mediaControls, MediaSlider)
390 PassRefPtrWillBeRawPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(MediaControls& mediaControls)
392 RefPtrWillBeRawPtr<MediaControlTimelineElement> timeline = adoptRefWillBeNoop(new MediaControlTimelineElement(mediaControls));
393 timeline->ensureUserAgentShadowRoot();
394 timeline->setType("range");
395 timeline->setAttribute(stepAttr, "any");
396 return timeline.release();
399 void MediaControlTimelineElement::defaultEventHandler(Event* event)
401 if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
404 if (!inDocument() || !document().isActive())
407 if (event->type() == EventTypeNames::mousedown)
408 mediaControls().beginScrubbing();
410 if (event->type() == EventTypeNames::mouseup)
411 mediaControls().endScrubbing();
413 MediaControlInputElement::defaultEventHandler(event);
415 if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
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);
430 RenderSlider* slider = toRenderSlider(renderer());
431 if (slider && slider->inDragMode())
432 mediaControls().updateCurrentTimeDisplay();
435 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
437 return inDocument() && document().isActive();
440 void MediaControlTimelineElement::setPosition(double currentTime)
442 setValue(String::number(currentTime));
445 void MediaControlTimelineElement::setDuration(double duration)
447 setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0);
450 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
452 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
456 bool MediaControlTimelineElement::keepEventInNode(Event* event)
458 return isUserInteractionEventForSlider(event);
461 // ----------------------------
463 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(MediaControls& mediaControls)
464 : MediaControlInputElement(mediaControls, MediaVolumeSlider)
468 PassRefPtrWillBeRawPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(MediaControls& mediaControls)
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();
478 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
480 if (event->isMouseEvent() && toMouseEvent(event)->button() != LeftButton)
483 if (!inDocument() || !document().isActive())
486 MediaControlInputElement::defaultEventHandler(event);
488 if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
491 double volume = value().toDouble();
492 mediaElement().setVolume(volume, ASSERT_NO_EXCEPTION);
493 mediaElement().setMuted(false);
496 bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
498 if (!inDocument() || !document().isActive())
501 return MediaControlInputElement::willRespondToMouseMoveEvents();
504 bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
506 if (!inDocument() || !document().isActive())
509 return MediaControlInputElement::willRespondToMouseClickEvents();
512 void MediaControlVolumeSliderElement::setVolume(double volume)
514 if (value().toDouble() != volume)
515 setValue(String::number(volume));
518 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
520 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
524 bool MediaControlVolumeSliderElement::keepEventInNode(Event* event)
526 return isUserInteractionEventForSlider(event);
529 // ----------------------------
531 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(MediaControls& mediaControls)
532 : MediaControlInputElement(mediaControls, MediaEnterFullscreenButton)
536 PassRefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(MediaControls& mediaControls)
538 RefPtrWillBeRawPtr<MediaControlFullscreenButtonElement> button = adoptRefWillBeNoop(new MediaControlFullscreenButtonElement(mediaControls));
539 button->ensureUserAgentShadowRoot();
540 button->setType("button");
542 return button.release();
545 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
547 if (event->type() == EventTypeNames::click) {
548 if (mediaElement().isFullscreen())
549 mediaElement().exitFullscreen();
551 mediaElement().enterFullscreen();
552 event->setDefaultHandled();
554 HTMLInputElement::defaultEventHandler(event);
557 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
559 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
563 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
565 setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
568 // ----------------------------
570 MediaControlCastButtonElement::MediaControlCastButtonElement(MediaControls& mediaControls, bool isOverlayButton)
571 : MediaControlInputElement(mediaControls, MediaCastOnButton), m_isOverlayButton(isOverlayButton)
573 setIsPlayingRemotely(false);
576 PassRefPtrWillBeRawPtr<MediaControlCastButtonElement> MediaControlCastButtonElement::create(MediaControls& mediaControls, bool isOverlayButton)
578 RefPtrWillBeRawPtr<MediaControlCastButtonElement> button = adoptRefWillBeNoop(new MediaControlCastButtonElement(mediaControls, isOverlayButton));
579 button->ensureUserAgentShadowRoot();
580 button->setType("button");
581 return button.release();
584 void MediaControlCastButtonElement::defaultEventHandler(Event* event)
586 if (event->type() == EventTypeNames::click) {
587 if (mediaElement().isPlayingRemotely()) {
588 mediaElement().requestRemotePlaybackControl();
590 mediaElement().requestRemotePlayback();
593 HTMLInputElement::defaultEventHandler(event);
596 const AtomicString& MediaControlCastButtonElement::shadowPseudoId() const
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;
603 void MediaControlCastButtonElement::setIsPlayingRemotely(bool isPlayingRemotely)
605 if (isPlayingRemotely) {
606 if (m_isOverlayButton) {
607 setDisplayType(MediaOverlayCastOnButton);
609 setDisplayType(MediaCastOnButton);
612 if (m_isOverlayButton) {
613 setDisplayType(MediaOverlayCastOffButton);
615 setDisplayType(MediaCastOffButton);
620 bool MediaControlCastButtonElement::keepEventInNode(Event* event)
622 return isUserInteractionEvent(event);
625 // ----------------------------
627 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(MediaControls& mediaControls)
628 : MediaControlTimeDisplayElement(mediaControls, MediaTimeRemainingDisplay)
632 PassRefPtrWillBeRawPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(MediaControls& mediaControls)
634 return adoptRefWillBeNoop(new MediaControlTimeRemainingDisplayElement(mediaControls));
637 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
639 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
643 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
645 return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
648 // ----------------------------
650 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(MediaControls& mediaControls)
651 : MediaControlTimeDisplayElement(mediaControls, MediaCurrentTimeDisplay)
655 PassRefPtrWillBeRawPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(MediaControls& mediaControls)
657 return adoptRefWillBeNoop(new MediaControlCurrentTimeDisplayElement(mediaControls));
660 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
662 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
666 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
668 return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
671 // ----------------------------
673 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(MediaControls& mediaControls)
674 : MediaControlDivElement(mediaControls, MediaTextTrackDisplayContainer)
679 PassRefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(MediaControls& mediaControls)
681 RefPtrWillBeRawPtr<MediaControlTextTrackContainerElement> element = adoptRefWillBeNoop(new MediaControlTextTrackContainerElement(mediaControls));
683 return element.release();
686 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*)
688 return new RenderTextTrackContainerElement(this);
691 const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
693 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
697 const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
699 return textTrackContainerElementShadowPseudoId();
702 void MediaControlTextTrackContainerElement::updateDisplay()
704 if (!mediaElement().closedCaptionsVisible()) {
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
712 if (isHTMLAudioElement(mediaElement()))
715 // 2. Let video be the media element or other playback mechanism.
716 HTMLVideoElement& video = toHTMLVideoElement(mediaElement());
718 // 3. Let output be an empty list of absolutely positioned CSS block boxes.
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.
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.
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.
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();
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.
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.
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();
755 ASSERT(cue->isActive());
756 if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
759 cue->updateDisplay(m_videoDisplaySize.size(), *this);
762 // 11. Return output.
769 void MediaControlTextTrackContainerElement::updateSizes()
771 if (!document().isActive())
776 if (!mediaElement().renderer() || !mediaElement().renderer()->isVideo())
778 videoBox = toRenderVideo(mediaElement().renderer())->videoBox();
780 if (m_videoDisplaySize == videoBox)
782 m_videoDisplaySize = videoBox;
784 float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
786 float fontSize = smallestDimension * 0.05f;
787 if (fontSize != m_fontSize) {
788 m_fontSize = fontSize;
789 setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX);
793 // ----------------------------