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 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.
33 #include "MediaControlElements.h"
35 #include "DOMTokenList.h"
36 #include "EventHandler.h"
37 #include "EventNames.h"
38 #include "ExceptionCodePlaceholder.h"
40 #include "GraphicsContext.h"
41 #include "HTMLVideoElement.h"
42 #include "ImageBuffer.h"
44 #include "LocalizedStrings.h"
46 #include "MediaControls.h"
47 #include "PageGroup.h"
48 #include "RenderLayer.h"
49 #include "RenderMediaControlElements.h"
50 #include "RenderSlider.h"
51 #include "RenderVideo.h"
52 #include "RenderView.h"
54 #include "ShadowRoot.h"
55 #if ENABLE(VIDEO_TRACK)
56 #include "TextTrackList.h"
59 #if ENABLE(WEBVTT_REGIONS)
60 #include "VTTRegionList.h"
65 using namespace HTMLNames;
67 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
68 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
70 MediaControlPanelElement::MediaControlPanelElement(Document& document)
71 : MediaControlDivElement(document, MediaControlsPanel)
72 , m_canBeDragged(false)
73 , m_isBeingDragged(false)
74 , m_isDisplayed(false)
76 , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
78 setPseudo(AtomicString("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
81 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document& document)
83 return adoptRef(new MediaControlPanelElement(document));
86 void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
94 auto renderer = this->renderer();
95 if (!renderer || !renderer->isBox())
98 Frame* frame = document().frame();
102 m_lastDragEventLocation = eventLocation;
104 frame->eventHandler().setCapturingMouseEventsElement(this);
106 m_isBeingDragged = true;
109 void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
111 if (!m_isBeingDragged)
114 LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
115 m_cumulativeDragOffset.move(distanceDragged);
116 m_lastDragEventLocation = eventLocation;
117 setPosition(m_cumulativeDragOffset);
120 void MediaControlPanelElement::endDrag()
122 if (!m_isBeingDragged)
125 m_isBeingDragged = false;
127 Frame* frame = document().frame();
131 frame->eventHandler().setCapturingMouseEventsElement(nullptr);
134 void MediaControlPanelElement::startTimer()
138 // The timer is required to set the property display:'none' on the panel,
139 // such that captions are correctly displayed at the bottom of the video
140 // at the end of the fadeout transition.
141 double duration = document().page() ? document().page()->theme().mediaControlsFadeOutDuration() : 0;
142 m_transitionTimer.startOneShot(duration);
145 void MediaControlPanelElement::stopTimer()
147 if (m_transitionTimer.isActive())
148 m_transitionTimer.stop();
151 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>&)
159 void MediaControlPanelElement::setPosition(const LayoutPoint& position)
161 double left = position.x();
162 double top = position.y();
164 // Set the left and top to control the panel's position; this depends on it being absolute positioned.
165 // Set the margin to zero since the position passed in will already include the effect of the margin.
166 setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
167 setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
168 setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
169 setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
171 classList()->add("dragged", IGNORE_EXCEPTION);
174 void MediaControlPanelElement::resetPosition()
176 removeInlineStyleProperty(CSSPropertyLeft);
177 removeInlineStyleProperty(CSSPropertyTop);
178 removeInlineStyleProperty(CSSPropertyMarginLeft);
179 removeInlineStyleProperty(CSSPropertyMarginTop);
181 classList()->remove("dragged", IGNORE_EXCEPTION);
183 m_cumulativeDragOffset.setX(0);
184 m_cumulativeDragOffset.setY(0);
187 void MediaControlPanelElement::makeOpaque()
192 double duration = document().page() ? document().page()->theme().mediaControlsFadeInDuration() : 0;
194 setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
195 setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
196 setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
204 void MediaControlPanelElement::makeTransparent()
209 double duration = document().page() ? document().page()->theme().mediaControlsFadeOutDuration() : 0;
211 setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
212 setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
213 setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
219 void MediaControlPanelElement::defaultEventHandler(Event* event)
221 MediaControlDivElement::defaultEventHandler(event);
223 if (event->isMouseEvent()) {
224 LayoutPoint location = toMouseEvent(event)->absoluteLocation();
225 if (event->type() == eventNames().mousedownEvent && event->target() == this) {
227 event->setDefaultHandled();
228 } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
229 continueDrag(location);
230 else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
231 continueDrag(location);
233 event->setDefaultHandled();
238 void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
240 if (m_canBeDragged == canBeDragged)
243 m_canBeDragged = canBeDragged;
249 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
251 m_isDisplayed = isDisplayed;
254 // ----------------------------
256 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document& document)
257 // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
258 : MediaControlDivElement(document, MediaControlsPanel)
260 setPseudo(AtomicString("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
263 PassRefPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(Document& document)
265 return adoptRef(new MediaControlPanelEnclosureElement(document));
268 // ----------------------------
270 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(Document& document)
271 // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
272 : MediaControlDivElement(document, MediaControlsPanel)
274 setPseudo(AtomicString("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
277 PassRefPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(Document& document)
279 return adoptRef(new MediaControlOverlayEnclosureElement(document));
282 // ----------------------------
284 MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document& document)
285 : MediaControlDivElement(document, MediaTimelineContainer)
287 setPseudo(AtomicString("-webkit-media-controls-timeline-container", AtomicString::ConstructFromLiteral));
290 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(Document& document)
292 RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(document));
294 return element.release();
297 void MediaControlTimelineContainerElement::setTimeDisplaysHidden(bool hidden)
299 for (unsigned i = 0; i < childNodeCount(); ++i) {
300 Node* child = childNode(i);
301 if (!child || !child->isElementNode())
303 Element* element = toElement(child);
304 if (element->shadowPseudoId() != getMediaControlTimeRemainingDisplayElementShadowPseudoId()
305 && element->shadowPseudoId() != getMediaControlCurrentTimeDisplayElementShadowPseudoId())
308 MediaControlTimeDisplayElement* timeDisplay = static_cast<MediaControlTimeDisplayElement*>(element);
316 RenderPtr<RenderElement> MediaControlTimelineContainerElement::createElementRenderer(PassRef<RenderStyle> style)
318 return createRenderer<RenderMediaControlTimelineContainer>(*this, WTF::move(style));
321 // ----------------------------
323 MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document& document)
324 : MediaControlDivElement(document, MediaVolumeSliderContainer)
326 setPseudo(AtomicString("-webkit-media-controls-volume-slider-container", AtomicString::ConstructFromLiteral));
329 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(Document& document)
331 RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(document));
333 return element.release();
336 RenderPtr<RenderElement> MediaControlVolumeSliderContainerElement::createElementRenderer(PassRef<RenderStyle> style)
338 return createRenderer<RenderMediaVolumeSliderContainer>(*this, WTF::move(style));
341 void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
343 if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
346 // Poor man's mouseleave event detection.
347 MouseEvent* mouseEvent = toMouseEvent(event);
348 EventTarget* relatedTarget = mouseEvent->relatedTarget();
349 if (!relatedTarget || !relatedTarget->toNode())
352 if (this->containsIncludingShadowDOM(relatedTarget->toNode()))
358 // ----------------------------
360 MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document& document)
361 : MediaControlDivElement(document, MediaStatusDisplay)
362 , m_stateBeingDisplayed(Nothing)
364 setPseudo(AtomicString("-webkit-media-controls-status-display", AtomicString::ConstructFromLiteral));
367 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(Document& document)
369 RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(document));
371 return element.release();
374 void MediaControlStatusDisplayElement::update()
376 // Get the new state that we'll have to display.
377 StateBeingDisplayed newStateToDisplay = Nothing;
379 if (mediaController()->readyState() <= MediaControllerInterface::HAVE_METADATA && mediaController()->hasCurrentSrc())
380 newStateToDisplay = Loading;
381 else if (mediaController()->isLiveStream())
382 newStateToDisplay = LiveBroadcast;
384 if (newStateToDisplay == m_stateBeingDisplayed)
387 if (m_stateBeingDisplayed == Nothing)
389 else if (newStateToDisplay == Nothing)
392 m_stateBeingDisplayed = newStateToDisplay;
394 switch (m_stateBeingDisplayed) {
396 setInnerText("", IGNORE_EXCEPTION);
399 setInnerText(mediaElementLoadingStateText(), IGNORE_EXCEPTION);
402 setInnerText(mediaElementLiveBroadcastStateText(), IGNORE_EXCEPTION);
407 // ----------------------------
409 MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document& document, MediaControls* controls)
410 : MediaControlMuteButtonElement(document, MediaMuteButton)
411 , m_controls(controls)
413 setPseudo(AtomicString("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
416 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document& document, MediaControls* controls)
420 RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
421 button->ensureUserAgentShadowRoot();
422 button->setType("button");
423 return button.release();
426 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
428 if (event->type() == eventNames().mouseoverEvent)
429 m_controls->showVolumeSlider();
431 MediaControlMuteButtonElement::defaultEventHandler(event);
434 // ----------------------------
436 MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document& document)
437 : MediaControlMuteButtonElement(document, MediaMuteButton)
439 setPseudo(AtomicString("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
442 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document& document)
444 RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
445 button->ensureUserAgentShadowRoot();
446 button->setType("button");
447 return button.release();
450 // ----------------------------
452 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document& document)
453 : MediaControlInputElement(document, MediaPlayButton)
455 setPseudo(AtomicString("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
458 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document& document)
460 RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
461 button->ensureUserAgentShadowRoot();
462 button->setType("button");
463 return button.release();
466 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
468 if (event->type() == eventNames().clickEvent) {
469 if (mediaController()->canPlay())
470 mediaController()->play();
472 mediaController()->pause();
474 event->setDefaultHandled();
476 HTMLInputElement::defaultEventHandler(event);
479 void MediaControlPlayButtonElement::updateDisplayType()
481 setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
484 // ----------------------------
486 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document& document)
487 : MediaControlInputElement(document, MediaOverlayPlayButton)
489 setPseudo(AtomicString("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
492 PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document& document)
494 RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
495 button->ensureUserAgentShadowRoot();
496 button->setType("button");
497 return button.release();
500 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
502 if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) {
503 mediaController()->play();
505 event->setDefaultHandled();
507 HTMLInputElement::defaultEventHandler(event);
510 void MediaControlOverlayPlayButtonElement::updateDisplayType()
512 if (mediaController()->canPlay()) {
518 // ----------------------------
520 MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(Document& document)
521 : MediaControlSeekButtonElement(document, MediaSeekForwardButton)
523 setPseudo(AtomicString("-webkit-media-controls-seek-forward-button", AtomicString::ConstructFromLiteral));
526 PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(Document& document)
528 RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(document));
529 button->ensureUserAgentShadowRoot();
530 button->setType("button");
531 return button.release();
534 // ----------------------------
536 MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(Document& document)
537 : MediaControlSeekButtonElement(document, MediaSeekBackButton)
539 setPseudo(AtomicString("-webkit-media-controls-seek-back-button", AtomicString::ConstructFromLiteral));
542 PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(Document& document)
544 RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(document));
545 button->ensureUserAgentShadowRoot();
546 button->setType("button");
547 return button.release();
550 // ----------------------------
552 MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document& document)
553 : MediaControlInputElement(document, MediaRewindButton)
555 setPseudo(AtomicString("-webkit-media-controls-rewind-button", AtomicString::ConstructFromLiteral));
558 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(Document& document)
560 RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(document));
561 button->ensureUserAgentShadowRoot();
562 button->setType("button");
563 return button.release();
566 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
568 if (event->type() == eventNames().clickEvent) {
569 mediaController()->setCurrentTime(std::max<double>(0, mediaController()->currentTime() - 30));
570 event->setDefaultHandled();
572 HTMLInputElement::defaultEventHandler(event);
575 // ----------------------------
577 MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document& document)
578 : MediaControlInputElement(document, MediaReturnToRealtimeButton)
580 setPseudo(AtomicString("-webkit-media-controls-return-to-realtime-button", AtomicString::ConstructFromLiteral));
583 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(Document& document)
585 RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(document));
586 button->ensureUserAgentShadowRoot();
587 button->setType("button");
589 return button.release();
592 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
594 if (event->type() == eventNames().clickEvent) {
595 mediaController()->returnToRealtime();
596 event->setDefaultHandled();
598 HTMLInputElement::defaultEventHandler(event);
601 // ----------------------------
603 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document& document, MediaControls* controls)
604 : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
605 #if PLATFORM(COCOA) || PLATFORM(WIN) || PLATFORM(GTK)
606 , m_controls(controls)
609 #if !PLATFORM(COCOA) && !PLATFORM(WIN) || !PLATFORM(GTK)
610 UNUSED_PARAM(controls);
612 setPseudo(AtomicString("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
615 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document& document, MediaControls* controls)
619 RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
620 button->ensureUserAgentShadowRoot();
621 button->setType("button");
623 return button.release();
626 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
628 bool captionsVisible = mediaController()->closedCaptionsVisible();
629 setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
630 setChecked(captionsVisible);
633 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
635 if (event->type() == eventNames().clickEvent) {
636 // FIXME: It's not great that the shared code is dictating behavior of platform-specific
637 // UI. Not all ports may want the closed captions button to toggle a list of tracks, so
638 // we have to use #if.
639 // https://bugs.webkit.org/show_bug.cgi?id=101877
640 #if !PLATFORM(COCOA) && !PLATFORM(WIN) && !PLATFORM(GTK)
641 mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
642 setChecked(mediaController()->closedCaptionsVisible());
645 m_controls->toggleClosedCaptionTrackList();
647 event->setDefaultHandled();
650 HTMLInputElement::defaultEventHandler(event);
653 // ----------------------------
655 MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement(Document& document)
656 : MediaControlDivElement(document, MediaClosedCaptionsContainer)
658 setPseudo(AtomicString("-webkit-media-controls-closed-captions-container", AtomicString::ConstructFromLiteral));
661 PassRefPtr<MediaControlClosedCaptionsContainerElement> MediaControlClosedCaptionsContainerElement::create(Document& document)
663 RefPtr<MediaControlClosedCaptionsContainerElement> element = adoptRef(new MediaControlClosedCaptionsContainerElement(document));
664 element->setAttribute(dirAttr, "auto");
666 return element.release();
669 // ----------------------------
671 MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement(Document& document, MediaControls* controls)
672 : MediaControlDivElement(document, MediaClosedCaptionsTrackList)
673 #if ENABLE(VIDEO_TRACK)
674 , m_controls(controls)
677 #if !ENABLE(VIDEO_TRACK)
678 UNUSED_PARAM(controls);
680 setPseudo(AtomicString("-webkit-media-controls-closed-captions-track-list", AtomicString::ConstructFromLiteral));
683 PassRefPtr<MediaControlClosedCaptionsTrackListElement> MediaControlClosedCaptionsTrackListElement::create(Document& document, MediaControls* controls)
686 RefPtr<MediaControlClosedCaptionsTrackListElement> element = adoptRef(new MediaControlClosedCaptionsTrackListElement(document, controls));
687 return element.release();
690 void MediaControlClosedCaptionsTrackListElement::defaultEventHandler(Event* event)
692 #if ENABLE(VIDEO_TRACK)
693 if (event->type() == eventNames().clickEvent) {
694 Node* target = event->target()->toNode();
695 if (!target || !target->isElementNode())
698 // When we created the elements in the track list, we gave them a custom
699 // attribute representing the index in the HTMLMediaElement's list of tracks.
700 // Check if the event target has such a custom element and, if so,
701 // tell the HTMLMediaElement to enable that track.
703 RefPtr<TextTrack> textTrack;
704 MenuItemToTrackMap::iterator iter = m_menuToTrackMap.find(toElement(target));
705 if (iter != m_menuToTrackMap.end())
706 textTrack = iter->value;
707 m_menuToTrackMap.clear();
708 m_controls->toggleClosedCaptionTrackList();
712 HTMLMediaElement* mediaElement = parentMediaElement(this);
716 mediaElement->setSelectedTextTrack(textTrack.get());
721 MediaControlDivElement::defaultEventHandler(event);
727 void MediaControlClosedCaptionsTrackListElement::updateDisplay()
729 #if ENABLE(VIDEO_TRACK)
730 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, selectedClassValue, ("selected", AtomicString::ConstructFromLiteral));
732 if (!mediaController()->hasClosedCaptions())
735 if (!document().page())
737 CaptionUserPreferences::CaptionDisplayMode displayMode = document().page()->group().captionPreferences()->captionDisplayMode();
739 HTMLMediaElement* mediaElement = parentMediaElement(this);
743 TextTrackList* trackList = mediaElement->textTracks();
744 if (!trackList || !trackList->length())
747 rebuildTrackListMenu();
749 RefPtr<Element> offMenuItem;
750 bool trackMenuItemSelected = false;
752 for (unsigned i = 0, length = m_menuItems.size(); i < length; ++i) {
753 RefPtr<Element> trackItem = m_menuItems[i];
755 RefPtr<TextTrack> textTrack;
756 MenuItemToTrackMap::iterator iter = m_menuToTrackMap.find(trackItem.get());
757 if (iter == m_menuToTrackMap.end())
759 textTrack = iter->value;
763 if (textTrack == TextTrack::captionMenuOffItem()) {
764 offMenuItem = trackItem;
768 if (textTrack == TextTrack::captionMenuAutomaticItem()) {
769 if (displayMode == CaptionUserPreferences::Automatic)
770 trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
772 trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
776 if (displayMode != CaptionUserPreferences::Automatic && textTrack->mode() == TextTrack::showingKeyword()) {
777 trackMenuItemSelected = true;
778 trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
780 trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
784 if (displayMode == CaptionUserPreferences::ForcedOnly && !trackMenuItemSelected)
785 offMenuItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
787 offMenuItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
792 void MediaControlClosedCaptionsTrackListElement::rebuildTrackListMenu()
794 #if ENABLE(VIDEO_TRACK)
795 // Remove any existing content.
798 m_menuToTrackMap.clear();
800 if (!mediaController()->hasClosedCaptions())
803 HTMLMediaElement* mediaElement = parentMediaElement(this);
807 TextTrackList* trackList = mediaElement->textTracks();
808 if (!trackList || !trackList->length())
811 if (!document().page())
813 CaptionUserPreferences* captionPreferences = document().page()->group().captionPreferences();
814 Vector<RefPtr<TextTrack>> tracksForMenu = captionPreferences->sortedTrackListForMenu(trackList);
816 RefPtr<Element> captionsHeader = document().createElement(h3Tag, ASSERT_NO_EXCEPTION);
817 captionsHeader->appendChild(document().createTextNode(textTrackSubtitlesText()));
818 appendChild(captionsHeader);
819 RefPtr<Element> captionsMenuList = document().createElement(ulTag, ASSERT_NO_EXCEPTION);
821 for (unsigned i = 0, length = tracksForMenu.size(); i < length; ++i) {
822 RefPtr<TextTrack> textTrack = tracksForMenu[i];
823 RefPtr<Element> menuItem = document().createElement(liTag, ASSERT_NO_EXCEPTION);
824 menuItem->appendChild(document().createTextNode(captionPreferences->displayNameForTrack(textTrack.get())));
825 captionsMenuList->appendChild(menuItem);
826 m_menuItems.append(menuItem);
827 m_menuToTrackMap.add(menuItem, textTrack);
830 appendChild(captionsMenuList);
834 // ----------------------------
836 MediaControlTimelineElement::MediaControlTimelineElement(Document& document, MediaControls* controls)
837 : MediaControlInputElement(document, MediaSlider)
838 , m_controls(controls)
840 setPseudo(AtomicString("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
843 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document& document, MediaControls* controls)
847 RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
848 timeline->ensureUserAgentShadowRoot();
849 timeline->setType("range");
850 timeline->setAttribute(precisionAttr, "float");
851 return timeline.release();
854 void MediaControlTimelineElement::defaultEventHandler(Event* event)
856 // Left button is 0. Rejects mouse events not from left button.
857 if (event->isMouseEvent() && toMouseEvent(event)->button())
863 if (event->type() == eventNames().mousedownEvent)
864 mediaController()->beginScrubbing();
866 if (event->type() == eventNames().mouseupEvent)
867 mediaController()->endScrubbing();
869 MediaControlInputElement::defaultEventHandler(event);
871 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
874 double time = value().toDouble();
875 if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime())
876 mediaController()->setCurrentTime(time);
878 RenderSlider* slider = toRenderSlider(renderer());
879 if (slider && slider->inDragMode())
880 m_controls->updateCurrentTimeDisplay();
884 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
891 #endif // !PLATFORM(IOS)
893 void MediaControlTimelineElement::setPosition(double currentTime)
895 setValue(String::number(currentTime));
898 void MediaControlTimelineElement::setDuration(double duration)
900 setAttribute(maxAttr, AtomicString::number(std::isfinite(duration) ? duration : 0));
903 // ----------------------------
905 MediaControlPanelVolumeSliderElement::MediaControlPanelVolumeSliderElement(Document& document)
906 : MediaControlVolumeSliderElement(document)
908 setPseudo(AtomicString("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
911 PassRefPtr<MediaControlPanelVolumeSliderElement> MediaControlPanelVolumeSliderElement::create(Document& document)
913 RefPtr<MediaControlPanelVolumeSliderElement> slider = adoptRef(new MediaControlPanelVolumeSliderElement(document));
914 slider->ensureUserAgentShadowRoot();
915 slider->setType("range");
916 slider->setAttribute(precisionAttr, "float");
917 slider->setAttribute(maxAttr, "1");
918 return slider.release();
921 // ----------------------------
923 MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(Document& document)
924 : MediaControlVolumeSliderElement(document)
926 setPseudo(AtomicString("-webkit-media-controls-fullscreen-volume-slider", AtomicString::ConstructFromLiteral));
929 PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(Document& document)
931 RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(document));
932 slider->ensureUserAgentShadowRoot();
933 slider->setType("range");
934 slider->setAttribute(precisionAttr, "float");
935 slider->setAttribute(maxAttr, "1");
936 return slider.release();
939 // ----------------------------
941 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document& document)
942 : MediaControlInputElement(document, MediaEnterFullscreenButton)
944 setPseudo(AtomicString("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
947 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document& document)
949 RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document));
950 button->ensureUserAgentShadowRoot();
951 button->setType("button");
953 return button.release();
956 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
958 if (event->type() == eventNames().clickEvent) {
959 #if ENABLE(FULLSCREEN_API)
960 // Only use the new full screen API if the fullScreenEnabled setting has
961 // been explicitly enabled. Otherwise, use the old fullscreen API. This
962 // allows apps which embed a WebView to retain the existing full screen
963 // video implementation without requiring them to implement their own full
965 if (document().settings() && document().settings()->fullScreenEnabled()) {
966 if (document().webkitIsFullScreen() && document().webkitCurrentFullScreenElement() == parentMediaElement(this))
967 document().webkitCancelFullScreen();
969 document().requestFullScreenForElement(parentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
972 mediaController()->enterFullscreen();
973 event->setDefaultHandled();
975 HTMLInputElement::defaultEventHandler(event);
978 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
980 setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
983 // ----------------------------
985 MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(Document& document)
986 : MediaControlInputElement(document, MediaUnMuteButton)
988 setPseudo(AtomicString("-webkit-media-controls-fullscreen-volume-min-button", AtomicString::ConstructFromLiteral));
991 PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(Document& document)
993 RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(document));
994 button->ensureUserAgentShadowRoot();
995 button->setType("button");
996 return button.release();
999 void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
1001 if (event->type() == eventNames().clickEvent) {
1002 ExceptionCode code = 0;
1003 mediaController()->setVolume(0, code);
1004 event->setDefaultHandled();
1006 HTMLInputElement::defaultEventHandler(event);
1009 // ----------------------------
1011 MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(Document& document)
1012 : MediaControlInputElement(document, MediaMuteButton)
1014 setPseudo(AtomicString("-webkit-media-controls-fullscreen-volume-max-button", AtomicString::ConstructFromLiteral));
1017 PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(Document& document)
1019 RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(document));
1020 button->ensureUserAgentShadowRoot();
1021 button->setType("button");
1022 return button.release();
1025 void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
1027 if (event->type() == eventNames().clickEvent) {
1028 ExceptionCode code = 0;
1029 mediaController()->setVolume(1, code);
1030 event->setDefaultHandled();
1032 HTMLInputElement::defaultEventHandler(event);
1035 // ----------------------------
1037 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document& document)
1038 : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay)
1040 setPseudo(getMediaControlTimeRemainingDisplayElementShadowPseudoId());
1043 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document& document)
1045 return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
1048 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
1050 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
1054 // ----------------------------
1056 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document& document)
1057 : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay)
1059 setPseudo(getMediaControlCurrentTimeDisplayElementShadowPseudoId());
1062 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document& document)
1064 return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
1067 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
1069 DEPRECATED_DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
1073 // ----------------------------
1075 #if ENABLE(VIDEO_TRACK)
1077 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document& document)
1078 : MediaControlDivElement(document, MediaTextTrackDisplayContainer)
1079 , m_updateTimer(this, &MediaControlTextTrackContainerElement::updateTimerFired)
1081 , m_fontSizeIsImportant(false)
1082 , m_updateTextTrackRepresentationStyle(false)
1084 setPseudo(AtomicString("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
1087 PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document& document)
1089 RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
1091 return element.release();
1094 RenderPtr<RenderElement> MediaControlTextTrackContainerElement::createElementRenderer(PassRef<RenderStyle> style)
1096 return createRenderer<RenderTextTrackContainerElement>(*this, WTF::move(style));
1099 void MediaControlTextTrackContainerElement::updateDisplay()
1101 if (!mediaController()->closedCaptionsVisible())
1104 HTMLMediaElement* mediaElement = parentMediaElement(this);
1105 // 1. If the media element is an audio element, or is another playback
1106 // mechanism with no rendering area, abort these steps. There is nothing to
1108 if (!mediaElement || !mediaElement->isVideo())
1111 // 2. Let video be the media element or other playback mechanism.
1112 HTMLVideoElement* video = toHTMLVideoElement(mediaElement);
1114 // 3. Let output be an empty list of absolutely positioned CSS block boxes.
1115 Vector<RefPtr<HTMLDivElement>> output;
1117 // 4. If the user agent is exposing a user interface for video, add to
1118 // output one or more completely transparent positioned CSS block boxes that
1119 // cover the same region as the user interface.
1121 // 5. If the last time these rules were run, the user agent was not exposing
1122 // a user interface for video, but now it is, let reset be true. Otherwise,
1123 // let reset be false.
1125 // There is nothing to be done explicitly for 4th and 5th steps, as
1126 // everything is handled through CSS. The caption box is on top of the
1127 // controls box, in a container set with the -webkit-box display property.
1129 // 6. Let tracks be the subset of video's list of text tracks that have as
1130 // their rules for updating the text track rendering these rules for
1131 // updating the display of WebVTT text tracks, and whose text track mode is
1132 // showing or showing by default.
1133 // 7. Let cues be an empty list of text track cues.
1134 // 8. For each track track in tracks, append to cues all the cues from
1135 // track's list of cues that have their text track cue active flag set.
1136 CueList activeCues = video->currentlyActiveCues();
1138 // 9. If reset is false, then, for each text track cue cue in cues: if cue's
1139 // text track cue display state has a set of CSS boxes, then add those boxes
1140 // to output, and remove cue from cues.
1142 // There is nothing explicitly to be done here, as all the caching occurs
1143 // within the TextTrackCue instance itself. If parameters of the cue change,
1144 // the display tree is cleared.
1146 // If the number of CSS boxes in the output is less than the number of cues
1147 // we wish to render (e.g., we are adding another cue in a set of roll-up
1148 // cues), remove all the existing CSS boxes representing the cues and re-add
1149 // them so that the new cue is at the bottom.
1150 if (childNodeCount() < activeCues.size())
1153 // 10. For each text track cue cue in cues that has not yet had
1154 // corresponding CSS boxes added to output, in text track cue order, run the
1155 // following substeps:
1156 for (size_t i = 0; i < activeCues.size(); ++i) {
1157 if (!mediaController()->closedCaptionsVisible())
1160 TextTrackCue* textTrackCue = activeCues[i].data();
1161 if (!textTrackCue->isRenderable())
1164 VTTCue* cue = toVTTCue(textTrackCue);
1166 ASSERT(cue->isActive());
1167 if (!cue->track() || !cue->track()->isRendered() || !cue->isActive() || cue->text().isEmpty())
1170 LOG(Media, "MediaControlTextTrackContainerElement::updateDisplay(%p) - adding and positioning cue #%zu: \"%s\", start=%.2f, end=%.2f, line=%.2f", this, i, cue->text().utf8().data(), cue->startTime(), cue->endTime(), cue->line());
1172 RefPtr<VTTCueBox> displayBox = cue->getDisplayTree(m_videoDisplaySize.size());
1173 #if ENABLE(WEBVTT_REGIONS)
1174 if (cue->track()->mode() == TextTrack::disabledKeyword())
1177 VTTRegion* region = cue->track()->regions()->getRegionById(cue->regionId());
1179 // If cue has an empty text track cue region identifier or there is no
1180 // WebVTT region whose region identifier is identical to cue's text
1181 // track cue region identifier, run the following substeps:
1183 if (displayBox->hasChildNodes() && !contains(displayBox.get())) {
1184 // Note: the display tree of a cue is removed when the active flag of the cue is unset.
1185 appendChild(displayBox, ASSERT_NO_EXCEPTION);
1186 cue->setFontSize(m_fontSize, m_videoDisplaySize.size(), m_fontSizeIsImportant);
1188 #if ENABLE(WEBVTT_REGIONS)
1190 // Let region be the WebVTT region whose region identifier
1191 // matches the text track cue region identifier of cue.
1192 RefPtr<HTMLDivElement> regionNode = region->getDisplayTree();
1194 // Append the region to the viewport, if it was not already.
1195 if (!contains(regionNode.get()))
1196 appendChild(region->getDisplayTree());
1198 region->appendTextTrackCueBox(displayBox);
1203 // 11. Return output.
1204 if (hasChildNodes()) {
1206 updateTextTrackRepresentation();
1209 clearTextTrackRepresentation();
1213 void MediaControlTextTrackContainerElement::updateActiveCuesFontSize()
1215 if (!document().page())
1218 HTMLMediaElement* mediaElement = parentMediaElement(this);
1222 float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
1223 float fontScale = document().page()->group().captionPreferences()->captionFontSizeScaleAndImportance(m_fontSizeIsImportant);
1224 m_fontSize = lroundf(smallestDimension * fontScale);
1226 CueList activeCues = mediaElement->currentlyActiveCues();
1227 for (size_t i = 0; i < activeCues.size(); ++i) {
1228 TextTrackCue* cue = activeCues[i].data();
1229 if (!cue->isRenderable())
1232 toVTTCue(cue)->setFontSize(m_fontSize, m_videoDisplaySize.size(), m_fontSizeIsImportant);
1237 void MediaControlTextTrackContainerElement::updateTimerFired(Timer<MediaControlTextTrackContainerElement>&)
1239 if (!document().page())
1242 if (m_textTrackRepresentation)
1243 updateStyleForTextTrackRepresentation();
1245 updateActiveCuesFontSize();
1249 void MediaControlTextTrackContainerElement::updateTextTrackRepresentation()
1251 HTMLMediaElement* mediaElement = parentMediaElement(this);
1255 if (!mediaElement->requiresTextTrackRepresentation())
1258 if (!m_textTrackRepresentation) {
1259 m_textTrackRepresentation = TextTrackRepresentation::create(this);
1260 m_updateTextTrackRepresentationStyle = true;
1261 mediaElement->setTextTrackRepresentation(m_textTrackRepresentation.get());
1264 m_textTrackRepresentation->update();
1265 updateStyleForTextTrackRepresentation();
1268 void MediaControlTextTrackContainerElement::clearTextTrackRepresentation()
1270 if (!m_textTrackRepresentation)
1273 m_textTrackRepresentation = nullptr;
1274 m_updateTextTrackRepresentationStyle = true;
1275 if (HTMLMediaElement* mediaElement = parentMediaElement(this))
1276 mediaElement->setTextTrackRepresentation(nullptr);
1277 updateStyleForTextTrackRepresentation();
1278 updateActiveCuesFontSize();
1281 void MediaControlTextTrackContainerElement::updateStyleForTextTrackRepresentation()
1283 if (!m_updateTextTrackRepresentationStyle)
1285 m_updateTextTrackRepresentationStyle = false;
1287 if (m_textTrackRepresentation) {
1288 setInlineStyleProperty(CSSPropertyWidth, m_videoDisplaySize.size().width(), CSSPrimitiveValue::CSS_PX);
1289 setInlineStyleProperty(CSSPropertyHeight, m_videoDisplaySize.size().height(), CSSPrimitiveValue::CSS_PX);
1290 setInlineStyleProperty(CSSPropertyPosition, CSSValueAbsolute);
1291 setInlineStyleProperty(CSSPropertyLeft, 0, CSSPrimitiveValue::CSS_PX);
1292 setInlineStyleProperty(CSSPropertyTop, 0, CSSPrimitiveValue::CSS_PX);
1296 removeInlineStyleProperty(CSSPropertyPosition);
1297 removeInlineStyleProperty(CSSPropertyWidth);
1298 removeInlineStyleProperty(CSSPropertyHeight);
1299 removeInlineStyleProperty(CSSPropertyLeft);
1300 removeInlineStyleProperty(CSSPropertyTop);
1303 void MediaControlTextTrackContainerElement::enteredFullscreen()
1305 if (hasChildNodes())
1306 updateTextTrackRepresentation();
1310 void MediaControlTextTrackContainerElement::exitedFullscreen()
1312 clearTextTrackRepresentation();
1316 void MediaControlTextTrackContainerElement::updateSizes(bool forceUpdate)
1318 HTMLMediaElement* mediaElement = parentMediaElement(this);
1322 if (!document().page())
1325 mediaElement->syncTextTrackBounds();
1328 if (m_textTrackRepresentation)
1329 videoBox = m_textTrackRepresentation->bounds();
1331 if (!mediaElement->renderer() || !mediaElement->renderer()->isVideo())
1333 videoBox = toRenderVideo(*mediaElement->renderer()).videoBox();
1336 if (!forceUpdate && m_videoDisplaySize == videoBox)
1339 m_videoDisplaySize = videoBox;
1340 m_updateTextTrackRepresentationStyle = true;
1342 // FIXME (121170): This function is called during layout, and should lay out the text tracks immediately.
1343 m_updateTimer.startOneShot(0);
1346 PassRefPtr<Image> MediaControlTextTrackContainerElement::createTextTrackRepresentationImage()
1348 if (!hasChildNodes())
1351 Frame* frame = document().frame();
1355 document().updateLayout();
1357 auto renderer = this->renderer();
1361 if (!renderer->hasLayer())
1364 RenderLayer* layer = toRenderLayerModelObject(renderer)->layer();
1366 float deviceScaleFactor = 1;
1367 if (Page* page = document().page())
1368 deviceScaleFactor = page->deviceScaleFactor();
1370 IntRect paintingRect = IntRect(IntPoint(), layer->size());
1372 std::unique_ptr<ImageBuffer> buffer(ImageBuffer::create(paintingRect.size(), deviceScaleFactor, ColorSpaceDeviceRGB));
1376 layer->paint(buffer->context(), paintingRect, LayoutSize(), PaintBehaviorFlattenCompositingLayers, nullptr, RenderLayer::PaintLayerPaintingCompositingAllPhases);
1378 return buffer->copyImage();
1381 void MediaControlTextTrackContainerElement::textTrackRepresentationBoundsChanged(const IntRect&)
1383 if (hasChildNodes())
1384 updateTextTrackRepresentation();
1388 #endif // ENABLE(VIDEO_TRACK)
1390 // ----------------------------
1392 } // namespace WebCore
1394 #endif // ENABLE(VIDEO)