• 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 "RuntimeEnabledFeatures.h"
34 #include "bindings/v8/ExceptionStatePlaceholder.h"
35 #include "core/dom/DOMTokenList.h"
36 #include "core/dom/FullscreenElementStack.h"
37 #include "core/dom/shadow/ShadowRoot.h"
38 #include "core/events/MouseEvent.h"
39 #include "core/events/ThreadLocalEventNames.h"
40 #include "core/html/HTMLVideoElement.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/frame/Frame.h"
46 #include "core/frame/Settings.h"
47 #include "core/rendering/RenderMediaControlElements.h"
48 #include "core/rendering/RenderSlider.h"
49 #include "core/rendering/RenderTheme.h"
50 #include "core/rendering/RenderVideo.h"
51 
52 namespace WebCore {
53 
54 using namespace HTMLNames;
55 
56 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId();
57 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId();
58 
59 static const double fadeInDuration = 0.1;
60 static const double fadeOutDuration = 0.3;
61 
MediaControlPanelElement(Document & document)62 MediaControlPanelElement::MediaControlPanelElement(Document& document)
63     : MediaControlDivElement(document, MediaControlsPanel)
64     , m_canBeDragged(false)
65     , m_isBeingDragged(false)
66     , m_isDisplayed(false)
67     , m_opaque(true)
68     , m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
69 {
70 }
71 
create(Document & document)72 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document& document)
73 {
74     return adoptRef(new MediaControlPanelElement(document));
75 }
76 
pseudo() const77 const AtomicString& MediaControlPanelElement::pseudo() const
78 {
79     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
80     return id;
81 }
82 
startDrag(const LayoutPoint & eventLocation)83 void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
84 {
85     if (!m_canBeDragged)
86         return;
87 
88     if (m_isBeingDragged)
89         return;
90 
91     RenderObject* renderer = this->renderer();
92     if (!renderer || !renderer->isBox())
93         return;
94 
95     Frame* frame = document().frame();
96     if (!frame)
97         return;
98 
99     m_lastDragEventLocation = eventLocation;
100 
101     frame->eventHandler().setCapturingMouseEventsNode(this);
102 
103     m_isBeingDragged = true;
104 }
105 
continueDrag(const LayoutPoint & eventLocation)106 void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
107 {
108     if (!m_isBeingDragged)
109         return;
110 
111     LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
112     m_cumulativeDragOffset.move(distanceDragged);
113     m_lastDragEventLocation = eventLocation;
114     setPosition(m_cumulativeDragOffset);
115 }
116 
endDrag()117 void MediaControlPanelElement::endDrag()
118 {
119     if (!m_isBeingDragged)
120         return;
121 
122     m_isBeingDragged = false;
123 
124     Frame* frame = document().frame();
125     if (!frame)
126         return;
127 
128     frame->eventHandler().setCapturingMouseEventsNode(0);
129 }
130 
startTimer()131 void MediaControlPanelElement::startTimer()
132 {
133     stopTimer();
134 
135     // The timer is required to set the property display:'none' on the panel,
136     // such that captions are correctly displayed at the bottom of the video
137     // at the end of the fadeout transition.
138     // FIXME: Racing a transition with a setTimeout like this is wrong.
139     m_transitionTimer.startOneShot(fadeOutDuration);
140 }
141 
stopTimer()142 void MediaControlPanelElement::stopTimer()
143 {
144     if (m_transitionTimer.isActive())
145         m_transitionTimer.stop();
146 }
147 
transitionTimerFired(Timer<MediaControlPanelElement> *)148 void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
149 {
150     if (!m_opaque)
151         hide();
152 
153     stopTimer();
154 }
155 
setPosition(const LayoutPoint & position)156 void MediaControlPanelElement::setPosition(const LayoutPoint& position)
157 {
158     double left = position.x();
159     double top = position.y();
160 
161     // Set the left and top to control the panel's position; this depends on it being absolute positioned.
162     // Set the margin to zero since the position passed in will already include the effect of the margin.
163     setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
164     setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
165     setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
166     setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
167 
168     classList()->add("dragged", IGNORE_EXCEPTION);
169 }
170 
resetPosition()171 void MediaControlPanelElement::resetPosition()
172 {
173     removeInlineStyleProperty(CSSPropertyLeft);
174     removeInlineStyleProperty(CSSPropertyTop);
175     removeInlineStyleProperty(CSSPropertyMarginLeft);
176     removeInlineStyleProperty(CSSPropertyMarginTop);
177 
178     classList()->remove("dragged", IGNORE_EXCEPTION);
179 
180     m_cumulativeDragOffset.setX(0);
181     m_cumulativeDragOffset.setY(0);
182 }
183 
makeOpaque()184 void MediaControlPanelElement::makeOpaque()
185 {
186     if (m_opaque)
187         return;
188 
189     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
190     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeInDuration, CSSPrimitiveValue::CSS_S);
191     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
192 
193     m_opaque = true;
194 
195     if (m_isDisplayed)
196         show();
197 }
198 
makeTransparent()199 void MediaControlPanelElement::makeTransparent()
200 {
201     if (!m_opaque)
202         return;
203 
204     setInlineStyleProperty(CSSPropertyTransitionProperty, CSSPropertyOpacity);
205     setInlineStyleProperty(CSSPropertyTransitionDuration, fadeOutDuration, CSSPrimitiveValue::CSS_S);
206     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
207 
208     m_opaque = false;
209     startTimer();
210 }
211 
defaultEventHandler(Event * event)212 void MediaControlPanelElement::defaultEventHandler(Event* event)
213 {
214     MediaControlDivElement::defaultEventHandler(event);
215 
216     if (event->isMouseEvent()) {
217         LayoutPoint location = toMouseEvent(event)->absoluteLocation();
218         if (event->type() == EventTypeNames::mousedown && event->target() == this) {
219             startDrag(location);
220             event->setDefaultHandled();
221         } else if (event->type() == EventTypeNames::mousemove && m_isBeingDragged)
222             continueDrag(location);
223         else if (event->type() == EventTypeNames::mouseup && m_isBeingDragged) {
224             continueDrag(location);
225             endDrag();
226             event->setDefaultHandled();
227         }
228     }
229 }
230 
setCanBeDragged(bool canBeDragged)231 void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
232 {
233     if (m_canBeDragged == canBeDragged)
234         return;
235 
236     m_canBeDragged = canBeDragged;
237 
238     if (!canBeDragged)
239         endDrag();
240 }
241 
setIsDisplayed(bool isDisplayed)242 void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
243 {
244     m_isDisplayed = isDisplayed;
245 }
246 
247 // ----------------------------
248 
MediaControlPanelEnclosureElement(Document & document)249 MediaControlPanelEnclosureElement::MediaControlPanelEnclosureElement(Document& document)
250     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
251     : MediaControlDivElement(document, MediaControlsPanel)
252 {
253 }
254 
create(Document & document)255 PassRefPtr<MediaControlPanelEnclosureElement> MediaControlPanelEnclosureElement::create(Document& document)
256 {
257     return adoptRef(new MediaControlPanelEnclosureElement(document));
258 }
259 
pseudo() const260 const AtomicString& MediaControlPanelEnclosureElement::pseudo() const
261 {
262     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure", AtomicString::ConstructFromLiteral));
263     return id;
264 }
265 
266 // ----------------------------
267 
MediaControlOverlayEnclosureElement(Document & document)268 MediaControlOverlayEnclosureElement::MediaControlOverlayEnclosureElement(Document& document)
269     // Mapping onto same MediaControlElementType as panel element, since it has similar properties.
270     : MediaControlDivElement(document, MediaControlsPanel)
271 {
272 }
273 
create(Document & document)274 PassRefPtr<MediaControlOverlayEnclosureElement> MediaControlOverlayEnclosureElement::create(Document& document)
275 {
276     return adoptRef(new MediaControlOverlayEnclosureElement(document));
277 }
278 
pseudo() const279 const AtomicString& MediaControlOverlayEnclosureElement::pseudo() const
280 {
281     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-enclosure", AtomicString::ConstructFromLiteral));
282     return id;
283 }
284 
285 // ----------------------------
286 
MediaControlPanelMuteButtonElement(Document & document,MediaControls * controls)287 MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document& document, MediaControls* controls)
288     : MediaControlMuteButtonElement(document, MediaMuteButton)
289     , m_controls(controls)
290 {
291 }
292 
create(Document & document,MediaControls * controls)293 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document& document, MediaControls* controls)
294 {
295     ASSERT(controls);
296 
297     RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
298     button->ensureUserAgentShadowRoot();
299     button->setType("button");
300     return button.release();
301 }
302 
defaultEventHandler(Event * event)303 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
304 {
305     if (event->type() == EventTypeNames::mouseover)
306         m_controls->showVolumeSlider();
307 
308     MediaControlMuteButtonElement::defaultEventHandler(event);
309 }
310 
pseudo() const311 const AtomicString& MediaControlPanelMuteButtonElement::pseudo() const
312 {
313     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
314     return id;
315 }
316 
317 // ----------------------------
318 
MediaControlVolumeSliderMuteButtonElement(Document & document)319 MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document& document)
320     : MediaControlMuteButtonElement(document, MediaMuteButton)
321 {
322 }
323 
create(Document & document)324 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document& document)
325 {
326     RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
327     button->ensureUserAgentShadowRoot();
328     button->setType("button");
329     return button.release();
330 }
331 
pseudo() const332 const AtomicString& MediaControlVolumeSliderMuteButtonElement::pseudo() const
333 {
334     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
335     return id;
336 }
337 
338 // ----------------------------
339 
MediaControlPlayButtonElement(Document & document)340 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document& document)
341     : MediaControlInputElement(document, MediaPlayButton)
342 {
343 }
344 
create(Document & document)345 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document& document)
346 {
347     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
348     button->ensureUserAgentShadowRoot();
349     button->setType("button");
350     return button.release();
351 }
352 
defaultEventHandler(Event * event)353 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
354 {
355     if (event->type() == EventTypeNames::click) {
356         if (mediaController()->canPlay())
357             mediaController()->play();
358         else
359             mediaController()->pause();
360         updateDisplayType();
361         event->setDefaultHandled();
362     }
363     HTMLInputElement::defaultEventHandler(event);
364 }
365 
updateDisplayType()366 void MediaControlPlayButtonElement::updateDisplayType()
367 {
368     setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
369 }
370 
pseudo() const371 const AtomicString& MediaControlPlayButtonElement::pseudo() const
372 {
373     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
374     return id;
375 }
376 
377 // ----------------------------
378 
MediaControlOverlayPlayButtonElement(Document & document)379 MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document& document)
380     : MediaControlInputElement(document, MediaOverlayPlayButton)
381 {
382 }
383 
create(Document & document)384 PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document& document)
385 {
386     RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
387     button->ensureUserAgentShadowRoot();
388     button->setType("button");
389     return button.release();
390 }
391 
defaultEventHandler(Event * event)392 void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
393 {
394     if (event->type() == EventTypeNames::click && mediaController()->canPlay()) {
395         mediaController()->play();
396         updateDisplayType();
397         event->setDefaultHandled();
398     }
399     HTMLInputElement::defaultEventHandler(event);
400 }
401 
updateDisplayType()402 void MediaControlOverlayPlayButtonElement::updateDisplayType()
403 {
404     if (mediaController()->canPlay()) {
405         show();
406     } else
407         hide();
408 }
409 
pseudo() const410 const AtomicString& MediaControlOverlayPlayButtonElement::pseudo() const
411 {
412     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
413     return id;
414 }
415 
416 
417 // ----------------------------
418 
MediaControlToggleClosedCaptionsButtonElement(Document & document,MediaControls *)419 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document& document, MediaControls*)
420     : MediaControlInputElement(document, MediaShowClosedCaptionsButton)
421 {
422 }
423 
create(Document & document,MediaControls * controls)424 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document& document, MediaControls* controls)
425 {
426     ASSERT(controls);
427 
428     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
429     button->ensureUserAgentShadowRoot();
430     button->setType("button");
431     button->hide();
432     return button.release();
433 }
434 
updateDisplayType()435 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
436 {
437     bool captionsVisible = mediaController()->closedCaptionsVisible();
438     setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
439     setChecked(captionsVisible);
440 }
441 
defaultEventHandler(Event * event)442 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
443 {
444     if (event->type() == EventTypeNames::click) {
445         mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
446         setChecked(mediaController()->closedCaptionsVisible());
447         updateDisplayType();
448         event->setDefaultHandled();
449     }
450 
451     HTMLInputElement::defaultEventHandler(event);
452 }
453 
pseudo() const454 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::pseudo() const
455 {
456     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
457     return id;
458 }
459 
460 // ----------------------------
461 
MediaControlTimelineElement(Document & document,MediaControls * controls)462 MediaControlTimelineElement::MediaControlTimelineElement(Document& document, MediaControls* controls)
463     : MediaControlInputElement(document, MediaSlider)
464     , m_controls(controls)
465 {
466 }
467 
create(Document & document,MediaControls * controls)468 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document& document, MediaControls* controls)
469 {
470     ASSERT(controls);
471 
472     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
473     timeline->ensureUserAgentShadowRoot();
474     timeline->setType("range");
475     timeline->setAttribute(stepAttr, "any");
476     return timeline.release();
477 }
478 
defaultEventHandler(Event * event)479 void MediaControlTimelineElement::defaultEventHandler(Event* event)
480 {
481     // Left button is 0. Rejects mouse events not from left button.
482     if (event->isMouseEvent() && toMouseEvent(event)->button())
483         return;
484 
485     if (!inDocument() || !document().isActive())
486         return;
487 
488     if (event->type() == EventTypeNames::mousedown)
489         mediaController()->beginScrubbing();
490 
491     if (event->type() == EventTypeNames::mouseup)
492         mediaController()->endScrubbing();
493 
494     MediaControlInputElement::defaultEventHandler(event);
495 
496     if (event->type() == EventTypeNames::mouseover || event->type() == EventTypeNames::mouseout || event->type() == EventTypeNames::mousemove)
497         return;
498 
499     double time = value().toDouble();
500     if (event->type() == EventTypeNames::input && time != mediaController()->currentTime())
501         mediaController()->setCurrentTime(time, IGNORE_EXCEPTION);
502 
503     RenderSlider* slider = toRenderSlider(renderer());
504     if (slider && slider->inDragMode())
505         m_controls->updateCurrentTimeDisplay();
506 }
507 
willRespondToMouseClickEvents()508 bool MediaControlTimelineElement::willRespondToMouseClickEvents()
509 {
510     return inDocument() && document().isActive();
511 }
512 
setPosition(double currentTime)513 void MediaControlTimelineElement::setPosition(double currentTime)
514 {
515     setValue(String::number(currentTime));
516 }
517 
setDuration(double duration)518 void MediaControlTimelineElement::setDuration(double duration)
519 {
520     setFloatingPointAttribute(maxAttr, std::isfinite(duration) ? duration : 0);
521 }
522 
523 
pseudo() const524 const AtomicString& MediaControlTimelineElement::pseudo() const
525 {
526     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
527     return id;
528 }
529 
530 // ----------------------------
531 
MediaControlPanelVolumeSliderElement(Document & document)532 MediaControlPanelVolumeSliderElement::MediaControlPanelVolumeSliderElement(Document& document)
533     : MediaControlVolumeSliderElement(document)
534 {
535 }
536 
create(Document & document)537 PassRefPtr<MediaControlPanelVolumeSliderElement> MediaControlPanelVolumeSliderElement::create(Document& document)
538 {
539     RefPtr<MediaControlPanelVolumeSliderElement> slider = adoptRef(new MediaControlPanelVolumeSliderElement(document));
540     slider->ensureUserAgentShadowRoot();
541     slider->setType("range");
542     slider->setAttribute(stepAttr, "any");
543     slider->setAttribute(maxAttr, "1");
544     return slider.release();
545 }
546 
pseudo() const547 const AtomicString& MediaControlPanelVolumeSliderElement::pseudo() const
548 {
549     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
550     return id;
551 }
552 
553 // ----------------------------
554 
MediaControlFullscreenButtonElement(Document & document)555 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document& document)
556     : MediaControlInputElement(document, MediaEnterFullscreenButton)
557 {
558 }
559 
create(Document & document)560 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document& document)
561 {
562     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document));
563     button->ensureUserAgentShadowRoot();
564     button->setType("button");
565     button->hide();
566     return button.release();
567 }
568 
defaultEventHandler(Event * event)569 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
570 {
571     if (event->type() == EventTypeNames::click) {
572         // Only use the new full screen API if the fullScreenEnabled setting has
573         // been explicitly enabled. Otherwise, use the old fullscreen API. This
574         // allows apps which embed a WebView to retain the existing full screen
575         // video implementation without requiring them to implement their own full
576         // screen behavior.
577         if (document().settings() && document().settings()->fullScreenEnabled()) {
578             if (FullscreenElementStack::isActiveFullScreenElement(toParentMediaElement(this)))
579                 FullscreenElementStack::from(&document())->webkitCancelFullScreen();
580             else
581                 FullscreenElementStack::from(&document())->requestFullScreenForElement(toParentMediaElement(this), 0, FullscreenElementStack::ExemptIFrameAllowFullScreenRequirement);
582         } else
583             mediaController()->enterFullscreen();
584         event->setDefaultHandled();
585     }
586     HTMLInputElement::defaultEventHandler(event);
587 }
588 
pseudo() const589 const AtomicString& MediaControlFullscreenButtonElement::pseudo() const
590 {
591     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
592     return id;
593 }
594 
setIsFullscreen(bool isFullscreen)595 void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
596 {
597     setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
598 }
599 
600 // ----------------------------
601 
MediaControlTimeRemainingDisplayElement(Document & document)602 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document& document)
603     : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay)
604 {
605 }
606 
create(Document & document)607 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document& document)
608 {
609     return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
610 }
611 
getMediaControlTimeRemainingDisplayElementShadowPseudoId()612 static const AtomicString& getMediaControlTimeRemainingDisplayElementShadowPseudoId()
613 {
614     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
615     return id;
616 }
617 
pseudo() const618 const AtomicString& MediaControlTimeRemainingDisplayElement::pseudo() const
619 {
620     return getMediaControlTimeRemainingDisplayElementShadowPseudoId();
621 }
622 
623 // ----------------------------
624 
MediaControlCurrentTimeDisplayElement(Document & document)625 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document& document)
626     : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay)
627 {
628 }
629 
create(Document & document)630 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document& document)
631 {
632     return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
633 }
634 
getMediaControlCurrentTimeDisplayElementShadowPseudoId()635 static const AtomicString& getMediaControlCurrentTimeDisplayElementShadowPseudoId()
636 {
637     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
638     return id;
639 }
640 
pseudo() const641 const AtomicString& MediaControlCurrentTimeDisplayElement::pseudo() const
642 {
643     return getMediaControlCurrentTimeDisplayElementShadowPseudoId();
644 }
645 
646 // ----------------------------
647 
MediaControlTextTrackContainerElement(Document & document)648 MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document& document)
649     : MediaControlDivElement(document, MediaTextTrackDisplayContainer)
650     , m_fontSize(0)
651 {
652 }
653 
create(Document & document)654 PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document& document)
655 {
656     RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
657     element->hide();
658     return element.release();
659 }
660 
createRenderer(RenderStyle *)661 RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderStyle*)
662 {
663     return new RenderTextTrackContainerElement(this);
664 }
665 
textTrackContainerElementShadowPseudoId()666 const AtomicString& MediaControlTextTrackContainerElement::textTrackContainerElementShadowPseudoId()
667 {
668     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
669     return id;
670 }
671 
pseudo() const672 const AtomicString& MediaControlTextTrackContainerElement::pseudo() const
673 {
674     return textTrackContainerElementShadowPseudoId();
675 }
676 
updateDisplay()677 void MediaControlTextTrackContainerElement::updateDisplay()
678 {
679     if (!mediaController()->closedCaptionsVisible()) {
680         removeChildren();
681         return;
682     }
683 
684     HTMLMediaElement* mediaElement = toParentMediaElement(this);
685     // 1. If the media element is an audio element, or is another playback
686     // mechanism with no rendering area, abort these steps. There is nothing to
687     // render.
688     if (!mediaElement || !mediaElement->isVideo())
689         return;
690 
691     // 2. Let video be the media element or other playback mechanism.
692     HTMLVideoElement* video = toHTMLVideoElement(mediaElement);
693 
694     // 3. Let output be an empty list of absolutely positioned CSS block boxes.
695     Vector<RefPtr<HTMLDivElement> > output;
696 
697     // 4. If the user agent is exposing a user interface for video, add to
698     // output one or more completely transparent positioned CSS block boxes that
699     // cover the same region as the user interface.
700 
701     // 5. If the last time these rules were run, the user agent was not exposing
702     // a user interface for video, but now it is, let reset be true. Otherwise,
703     // let reset be false.
704 
705     // There is nothing to be done explicitly for 4th and 5th steps, as
706     // everything is handled through CSS. The caption box is on top of the
707     // controls box, in a container set with the -webkit-box display property.
708 
709     // 6. Let tracks be the subset of video's list of text tracks that have as
710     // their rules for updating the text track rendering these rules for
711     // updating the display of WebVTT text tracks, and whose text track mode is
712     // showing or showing by default.
713     // 7. Let cues be an empty list of text track cues.
714     // 8. For each track track in tracks, append to cues all the cues from
715     // track's list of cues that have their text track cue active flag set.
716     CueList activeCues = video->currentlyActiveCues();
717 
718     // 9. If reset is false, then, for each text track cue cue in cues: if cue's
719     // text track cue display state has a set of CSS boxes, then add those boxes
720     // to output, and remove cue from cues.
721 
722     // There is nothing explicitly to be done here, as all the caching occurs
723     // within the TextTrackCue instance itself. If parameters of the cue change,
724     // the display tree is cleared.
725 
726     // 10. For each text track cue cue in cues that has not yet had
727     // corresponding CSS boxes added to output, in text track cue order, run the
728     // following substeps:
729     for (size_t i = 0; i < activeCues.size(); ++i) {
730         TextTrackCue* cue = activeCues[i].data();
731 
732         ASSERT(cue->isActive());
733         if (!cue->track() || !cue->track()->isRendered() || !cue->isActive())
734             continue;
735 
736         cue->updateDisplay(m_videoDisplaySize.size(), *this);
737     }
738 
739     // 11. Return output.
740     if (hasChildNodes())
741         show();
742     else
743         hide();
744 }
745 
updateSizes(bool forceUpdate)746 void MediaControlTextTrackContainerElement::updateSizes(bool forceUpdate)
747 {
748     HTMLMediaElement* mediaElement = toParentMediaElement(this);
749     if (!mediaElement)
750         return;
751 
752     if (!document().isActive())
753         return;
754 
755     IntRect videoBox;
756 
757     if (!mediaElement->renderer() || !mediaElement->renderer()->isVideo())
758         return;
759     videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
760 
761     if (!forceUpdate && m_videoDisplaySize == videoBox)
762         return;
763     m_videoDisplaySize = videoBox;
764 
765     float smallestDimension = std::min(m_videoDisplaySize.size().height(), m_videoDisplaySize.size().width());
766 
767     float fontSize = smallestDimension * 0.05f;
768     if (fontSize != m_fontSize) {
769         m_fontSize = fontSize;
770         setInlineStyleProperty(CSSPropertyFontSize, fontSize, CSSPrimitiveValue::CSS_PX);
771     }
772 }
773 
774 // ----------------------------
775 
776 } // namespace WebCore
777