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