2
* Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
4
* Redistribution and use in source and binary forms, with or without
5
* modification, are permitted provided that the following conditions
8
* 1. Redistributions of source code must retain the above copyright
9
* notice, this list of conditions and the following disclaimer.
10
* 2. Redistributions in binary form must reproduce the above copyright
11
* notice, this list of conditions and the following disclaimer in the
12
* documentation and/or other materials provided with the distribution.
13
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14
* its contributors may be used to endorse or promote products derived
15
* from this software without specific prior written permission.
17
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
#include "MediaControlElements.h"
35
#include "CSSStyleDeclaration.h"
36
#include "CSSValueKeywords.h"
37
#include "DOMTokenList.h"
38
#include "EventNames.h"
39
#include "EventTarget.h"
40
#include "FloatConversion.h"
41
#include "FloatPoint.h"
43
#include "HTMLDivElement.h"
44
#include "HTMLMediaElement.h"
45
#include "HTMLNames.h"
46
#include "HTMLVideoElement.h"
48
#include "LayoutRepainter.h"
49
#include "LocalizedStrings.h"
50
#include "MediaControls.h"
51
#include "MouseEvent.h"
53
#include "PageGroup.h"
54
#include "RenderDeprecatedFlexibleBox.h"
55
#include "RenderInline.h"
56
#include "RenderMedia.h"
57
#include "RenderSlider.h"
58
#include "RenderText.h"
59
#include "RenderTheme.h"
60
#include "RenderVideo.h"
61
#include "RenderView.h"
62
#include "ScriptController.h"
64
#include "StyleResolver.h"
66
#if ENABLE(VIDEO_TRACK)
67
#include "TextTrack.h"
68
#include "TextTrackList.h"
73
using namespace HTMLNames;
76
// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
77
static const float cSkipRepeatDelay = 0.1f;
78
static const float cSkipTime = 0.2f;
79
static const float cScanRepeatDelay = 1.5f;
80
static const float cScanMaximumRate = 8;
82
#if ENABLE(VIDEO_TRACK)
83
static const char* textTracksOffAttrValue = "-1"; // This must match HTMLMediaElement::textTracksOffIndex()
84
static const int textTracksIndexNotFound = -2;
87
HTMLMediaElement* toParentMediaElement(Node* node)
91
Node* mediaNode = node->shadowHost();
94
if (!mediaNode || !mediaNode->isElementNode() || !static_cast<Element*>(mediaNode)->isMediaElement())
97
return static_cast<HTMLMediaElement*>(mediaNode);
100
MediaControlElementType mediaControlElementType(Node* node)
102
ASSERT(node->isMediaControlElement());
103
HTMLElement* element = toHTMLElement(node);
104
if (element->hasTagName(inputTag))
105
return static_cast<MediaControlInputElement*>(element)->displayType();
106
return static_cast<MediaControlElement*>(element)->displayType();
109
#if ENABLE(VIDEO_TRACK)
110
static const AtomicString& trackIndexAttributeName()
112
DEFINE_STATIC_LOCAL(AtomicString, name, ("x-webkit-track-index", AtomicString::ConstructFromLiteral));
116
static int trackListIndexForElement(Element* element)
118
const AtomicString trackIndexAttributeValue = element->getAttribute(trackIndexAttributeName());
119
if (trackIndexAttributeValue.isNull() || trackIndexAttributeValue.isEmpty())
120
return textTracksIndexNotFound;
122
int trackIndex = trackIndexAttributeValue.toInt(&ok);
124
return textTracksIndexNotFound;
129
// ----------------------------
131
MediaControlElement::MediaControlElement(Document* document)
132
: HTMLDivElement(divTag, document)
133
, m_mediaController(0)
137
void MediaControlElement::show()
139
removeInlineStyleProperty(CSSPropertyDisplay);
142
void MediaControlElement::hide()
144
setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
147
bool MediaControlElement::isShowing() const
149
const StylePropertySet* propertySet = inlineStyle();
150
// Following the code from show() and hide() above, we only have
151
// to check for the presense of inline display.
152
return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay));
155
// ----------------------------
157
inline MediaControlPanelElement::MediaControlPanelElement(Document* document)
158
: MediaControlElement(document)
159
, m_canBeDragged(false)
160
, m_isBeingDragged(false)
161
, m_isDisplayed(false)
163
, m_transitionTimer(this, &MediaControlPanelElement::transitionTimerFired)
167
PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(Document* document)
169
return adoptRef(new MediaControlPanelElement(document));
172
MediaControlElementType MediaControlPanelElement::displayType() const
174
return MediaControlsPanel;
177
const AtomicString& MediaControlPanelElement::shadowPseudoId() const
179
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel", AtomicString::ConstructFromLiteral));
183
void MediaControlPanelElement::startDrag(const LayoutPoint& eventLocation)
188
if (m_isBeingDragged)
191
RenderObject* renderer = this->renderer();
192
if (!renderer || !renderer->isBox())
195
Frame* frame = document()->frame();
199
m_lastDragEventLocation = eventLocation;
201
frame->eventHandler()->setCapturingMouseEventsNode(this);
203
m_isBeingDragged = true;
206
void MediaControlPanelElement::continueDrag(const LayoutPoint& eventLocation)
208
if (!m_isBeingDragged)
211
LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
212
m_cumulativeDragOffset.move(distanceDragged);
213
m_lastDragEventLocation = eventLocation;
214
setPosition(m_cumulativeDragOffset);
217
void MediaControlPanelElement::endDrag()
219
if (!m_isBeingDragged)
222
m_isBeingDragged = false;
224
Frame* frame = document()->frame();
228
frame->eventHandler()->setCapturingMouseEventsNode(0);
231
void MediaControlPanelElement::startTimer()
235
// The timer is required to set the property display:'none' on the panel,
236
// such that captions are correctly displayed at the bottom of the video
237
// at the end of the fadeout transition.
238
double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
239
m_transitionTimer.startOneShot(duration);
242
void MediaControlPanelElement::stopTimer()
244
if (m_transitionTimer.isActive())
245
m_transitionTimer.stop();
249
void MediaControlPanelElement::transitionTimerFired(Timer<MediaControlPanelElement>*)
257
void MediaControlPanelElement::setPosition(const LayoutPoint& position)
259
double left = position.x();
260
double top = position.y();
262
// Set the left and top to control the panel's position; this depends on it being absolute positioned.
263
// Set the margin to zero since the position passed in will already include the effect of the margin.
264
setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
265
setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
266
setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
267
setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
269
ExceptionCode ignored;
270
classList()->add("dragged", ignored);
273
void MediaControlPanelElement::resetPosition()
275
removeInlineStyleProperty(CSSPropertyLeft);
276
removeInlineStyleProperty(CSSPropertyTop);
277
removeInlineStyleProperty(CSSPropertyMarginLeft);
278
removeInlineStyleProperty(CSSPropertyMarginTop);
280
ExceptionCode ignored;
281
classList()->remove("dragged", ignored);
283
m_cumulativeDragOffset.setX(0);
284
m_cumulativeDragOffset.setY(0);
287
void MediaControlPanelElement::makeOpaque()
292
double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0;
294
setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
295
setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
296
setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
304
void MediaControlPanelElement::makeTransparent()
309
double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
311
setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
312
setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
313
setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
319
void MediaControlPanelElement::defaultEventHandler(Event* event)
321
MediaControlElement::defaultEventHandler(event);
323
if (event->isMouseEvent()) {
324
LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation();
325
if (event->type() == eventNames().mousedownEvent && event->target() == this) {
327
event->setDefaultHandled();
328
} else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
329
continueDrag(location);
330
else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
331
continueDrag(location);
333
event->setDefaultHandled();
338
void MediaControlPanelElement::setCanBeDragged(bool canBeDragged)
340
if (m_canBeDragged == canBeDragged)
343
m_canBeDragged = canBeDragged;
349
void MediaControlPanelElement::setIsDisplayed(bool isDisplayed)
351
m_isDisplayed = isDisplayed;
354
// ----------------------------
356
inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document)
357
: MediaControlElement(document)
361
PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(Document* document)
363
RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(document));
365
return element.release();
368
MediaControlElementType MediaControlTimelineContainerElement::displayType() const
370
return MediaTimelineContainer;
373
const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
375
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container", AtomicString::ConstructFromLiteral));
379
// ----------------------------
381
class RenderMediaVolumeSliderContainer : public RenderBlock {
383
RenderMediaVolumeSliderContainer(Node*);
386
virtual void layout();
389
RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
394
void RenderMediaVolumeSliderContainer::layout()
396
RenderBlock::layout();
398
if (style()->display() == NONE || !nextSibling() || !nextSibling()->isBox())
401
RenderBox* buttonBox = toRenderBox(nextSibling());
402
int absoluteOffsetTop = buttonBox->localToAbsolute(FloatPoint(0, -size().height())).y();
404
LayoutStateDisabler layoutStateDisabler(view());
406
// If the slider would be rendered outside the page, it should be moved below the controls.
407
if (UNLIKELY(absoluteOffsetTop < 0))
408
setY(buttonBox->offsetTop() + theme()->volumeSliderOffsetFromMuteButton(buttonBox, pixelSnappedSize()).y());
411
inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* document)
412
: MediaControlElement(document)
416
PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(Document* document)
418
RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(document));
420
return element.release();
423
RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
425
return new (arena) RenderMediaVolumeSliderContainer(this);
428
void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
430
if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
433
// Poor man's mouseleave event detection.
434
MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
435
if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
438
if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
444
MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const
446
return MediaVolumeSliderContainer;
449
const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const
451
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container", AtomicString::ConstructFromLiteral));
455
// ----------------------------
457
inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document)
458
: MediaControlElement(document)
459
, m_stateBeingDisplayed(Nothing)
463
PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(Document* document)
465
RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(document));
467
return element.release();
470
void MediaControlStatusDisplayElement::update()
472
// Get the new state that we'll have to display.
473
StateBeingDisplayed newStateToDisplay = Nothing;
475
if (mediaController()->readyState() <= MediaControllerInterface::HAVE_METADATA && mediaController()->hasCurrentSrc())
476
newStateToDisplay = Loading;
477
else if (mediaController()->isLiveStream())
478
newStateToDisplay = LiveBroadcast;
480
if (newStateToDisplay == m_stateBeingDisplayed)
485
if (m_stateBeingDisplayed == Nothing)
487
else if (newStateToDisplay == Nothing)
490
m_stateBeingDisplayed = newStateToDisplay;
492
switch (m_stateBeingDisplayed) {
497
setInnerText(mediaElementLoadingStateText(), e);
500
setInnerText(mediaElementLiveBroadcastStateText(), e);
505
MediaControlElementType MediaControlStatusDisplayElement::displayType() const
507
return MediaStatusDisplay;
510
const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const
512
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display", AtomicString::ConstructFromLiteral));
516
// ----------------------------
518
MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType)
519
: HTMLInputElement(inputTag, document, 0, false)
520
, m_mediaController(0)
521
, m_displayType(displayType)
525
void MediaControlInputElement::show()
527
removeInlineStyleProperty(CSSPropertyDisplay);
530
void MediaControlInputElement::hide()
532
setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
536
void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
538
if (displayType == m_displayType)
541
m_displayType = displayType;
542
if (RenderObject* object = renderer())
546
// ----------------------------
548
inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType)
549
: MediaControlInputElement(document, displayType)
553
void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
555
if (event->type() == eventNames().clickEvent) {
556
mediaController()->setMuted(!mediaController()->muted());
557
event->setDefaultHandled();
560
HTMLInputElement::defaultEventHandler(event);
563
void MediaControlMuteButtonElement::changedMute()
568
void MediaControlMuteButtonElement::updateDisplayType()
570
setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton);
573
// ----------------------------
575
inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(Document* document, MediaControls* controls)
576
: MediaControlMuteButtonElement(document, MediaMuteButton)
577
, m_controls(controls)
581
PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(Document* document, MediaControls* controls)
585
RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(document, controls));
586
button->createShadowSubtree();
587
button->setType("button");
588
return button.release();
591
void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
593
if (event->type() == eventNames().mouseoverEvent)
594
m_controls->showVolumeSlider();
596
MediaControlMuteButtonElement::defaultEventHandler(event);
599
const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
601
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button", AtomicString::ConstructFromLiteral));
605
// ----------------------------
607
inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(Document* document)
608
: MediaControlMuteButtonElement(document, MediaMuteButton)
612
PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(Document* document)
614
RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(document));
615
button->createShadowSubtree();
616
button->setType("button");
617
return button.release();
620
const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
622
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button", AtomicString::ConstructFromLiteral));
626
// ----------------------------
628
inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document)
629
: MediaControlInputElement(document, MediaPlayButton)
633
PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(Document* document)
635
RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(document));
636
button->createShadowSubtree();
637
button->setType("button");
638
return button.release();
641
void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
643
if (event->type() == eventNames().clickEvent) {
644
if (mediaController()->canPlay())
645
mediaController()->play();
647
mediaController()->pause();
649
event->setDefaultHandled();
651
HTMLInputElement::defaultEventHandler(event);
654
void MediaControlPlayButtonElement::updateDisplayType()
656
setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
659
const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
661
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button", AtomicString::ConstructFromLiteral));
665
// ----------------------------
667
inline MediaControlOverlayPlayButtonElement::MediaControlOverlayPlayButtonElement(Document* document)
668
: MediaControlInputElement(document, MediaOverlayPlayButton)
672
PassRefPtr<MediaControlOverlayPlayButtonElement> MediaControlOverlayPlayButtonElement::create(Document* document)
674
RefPtr<MediaControlOverlayPlayButtonElement> button = adoptRef(new MediaControlOverlayPlayButtonElement(document));
675
button->createShadowSubtree();
676
button->setType("button");
677
return button.release();
680
void MediaControlOverlayPlayButtonElement::defaultEventHandler(Event* event)
682
if (event->type() == eventNames().clickEvent && mediaController()->canPlay()) {
683
mediaController()->play();
685
event->setDefaultHandled();
687
HTMLInputElement::defaultEventHandler(event);
690
void MediaControlOverlayPlayButtonElement::updateDisplayType()
692
if (mediaController()->canPlay()) {
694
setDisplayType(MediaOverlayPlayButton);
699
const AtomicString& MediaControlOverlayPlayButtonElement::shadowPseudoId() const
701
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-overlay-play-button", AtomicString::ConstructFromLiteral));
705
// ----------------------------
707
inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType)
708
: MediaControlInputElement(document, displayType)
709
, m_actionOnStop(Nothing)
711
, m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
715
void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
717
// Set the mousedown and mouseup events as defaultHandled so they
718
// do not trigger drag start or end actions in MediaControlPanelElement.
719
if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
720
event->setDefaultHandled();
723
void MediaControlSeekButtonElement::setActive(bool flag, bool pause)
725
if (flag == active())
733
MediaControlInputElement::setActive(flag, pause);
736
void MediaControlSeekButtonElement::startTimer()
738
m_seekType = mediaController()->supportsScanning() ? Scan : Skip;
740
if (m_seekType == Skip) {
741
// Seeking by skipping requires the video to be paused during seeking.
742
m_actionOnStop = mediaController()->paused() ? Nothing : Play;
743
mediaController()->pause();
745
// Seeking by scanning requires the video to be playing during seeking.
746
m_actionOnStop = mediaController()->paused() ? Pause : Nothing;
747
mediaController()->play();
748
mediaController()->setPlaybackRate(nextRate());
751
m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay);
754
void MediaControlSeekButtonElement::stopTimer()
756
if (m_seekType == Scan)
757
mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate());
759
if (m_actionOnStop == Play)
760
mediaController()->play();
761
else if (m_actionOnStop == Pause)
762
mediaController()->pause();
764
if (m_seekTimer.isActive())
768
float MediaControlSeekButtonElement::nextRate() const
770
float rate = std::min(cScanMaximumRate, fabsf(mediaController()->playbackRate() * 2));
771
if (!isForwardButton())
776
void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
778
if (m_seekType == Skip) {
780
float skipTime = isForwardButton() ? cSkipTime : -cSkipTime;
781
mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, ec);
783
mediaController()->setPlaybackRate(nextRate());
786
// ----------------------------
788
inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(Document* document)
789
: MediaControlSeekButtonElement(document, MediaSeekForwardButton)
793
PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(Document* document)
795
RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(document));
796
button->createShadowSubtree();
797
button->setType("button");
798
return button.release();
801
const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const
803
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button", AtomicString::ConstructFromLiteral));
807
// ----------------------------
809
inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(Document* document)
810
: MediaControlSeekButtonElement(document, MediaSeekBackButton)
814
PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(Document* document)
816
RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(document));
817
button->createShadowSubtree();
818
button->setType("button");
819
return button.release();
822
const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const
824
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button", AtomicString::ConstructFromLiteral));
828
// ----------------------------
830
inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document)
831
: MediaControlInputElement(document, MediaRewindButton)
835
PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(Document* document)
837
RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(document));
838
button->createShadowSubtree();
839
button->setType("button");
840
return button.release();
843
void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
845
if (event->type() == eventNames().clickEvent) {
846
ExceptionCode ignoredCode;
847
mediaController()->setCurrentTime(max(0.0f, mediaController()->currentTime() - 30), ignoredCode);
848
event->setDefaultHandled();
850
HTMLInputElement::defaultEventHandler(event);
853
const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
855
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button", AtomicString::ConstructFromLiteral));
859
// ----------------------------
861
inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document)
862
: MediaControlInputElement(document, MediaReturnToRealtimeButton)
866
PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(Document* document)
868
RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(document));
869
button->createShadowSubtree();
870
button->setType("button");
872
return button.release();
875
void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
877
if (event->type() == eventNames().clickEvent) {
878
mediaController()->returnToRealtime();
879
event->setDefaultHandled();
881
HTMLInputElement::defaultEventHandler(event);
884
const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
886
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button", AtomicString::ConstructFromLiteral));
890
// ----------------------------
892
inline MediaControlClosedCaptionsContainerElement::MediaControlClosedCaptionsContainerElement(Document* document)
893
: MediaControlElement(document)
897
PassRefPtr<MediaControlClosedCaptionsContainerElement> MediaControlClosedCaptionsContainerElement::create(Document* document)
899
RefPtr<MediaControlClosedCaptionsContainerElement> element = adoptRef(new MediaControlClosedCaptionsContainerElement(document));
901
return element.release();
904
const AtomicString& MediaControlClosedCaptionsContainerElement::shadowPseudoId() const
906
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-container", AtomicString::ConstructFromLiteral));
910
// ----------------------------
912
inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* document, MediaControls* controls)
913
: MediaControlInputElement(document, MediaShowClosedCaptionsButton)
915
, m_controls(controls)
919
UNUSED_PARAM(controls);
923
PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(Document* document, MediaControls* controls)
927
RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(document, controls));
928
button->createShadowSubtree();
929
button->setType("button");
931
return button.release();
934
void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
936
bool captionsVisible = mediaController()->closedCaptionsVisible();
937
setDisplayType(captionsVisible ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
938
setChecked(captionsVisible);
941
void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
943
if (event->type() == eventNames().clickEvent) {
944
// FIXME: It's not great that the shared code is dictating behavior of platform-specific
945
// UI. Not all ports may want the closed captions button to toggle a list of tracks, so
946
// we have to use #if.
947
// https://bugs.webkit.org/show_bug.cgi?id=101877
949
mediaController()->setClosedCaptionsVisible(!mediaController()->closedCaptionsVisible());
950
setChecked(mediaController()->closedCaptionsVisible());
953
m_controls->toggleClosedCaptionTrackList();
955
event->setDefaultHandled();
958
HTMLInputElement::defaultEventHandler(event);
961
const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
963
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button", AtomicString::ConstructFromLiteral));
967
// ----------------------------
969
inline MediaControlClosedCaptionsTrackListElement::MediaControlClosedCaptionsTrackListElement(Document* document, MediaControls* controls)
970
: MediaControlElement(document)
971
, m_controls(controls)
975
PassRefPtr<MediaControlClosedCaptionsTrackListElement> MediaControlClosedCaptionsTrackListElement::create(Document* document, MediaControls* controls)
978
RefPtr<MediaControlClosedCaptionsTrackListElement> element = adoptRef(new MediaControlClosedCaptionsTrackListElement(document, controls));
979
return element.release();
982
void MediaControlClosedCaptionsTrackListElement::defaultEventHandler(Event* event)
984
#if ENABLE(VIDEO_TRACK)
985
if (event->type() == eventNames().clickEvent) {
986
// FIXME: Add modifier key for exclusivity override.
987
// http://webkit.org/b/103361
989
Node* target = event->target()->toNode();
990
if (!target || !target->isElementNode())
993
// When we created the elements in the track list, we gave them a custom
994
// attribute representing the index in the HTMLMediaElement's list of tracks.
995
// Check if the event target has such a custom element and, if so,
996
// tell the HTMLMediaElement to enable that track.
998
int trackIndex = trackListIndexForElement(toElement(target));
999
if (trackIndex == textTracksIndexNotFound)
1002
HTMLMediaElement* mediaElement = toParentMediaElement(this);
1006
mediaElement->toggleTrackAtIndex(trackIndex);
1008
// We've selected a track to display, so we can now close the menu.
1009
m_controls->toggleClosedCaptionTrackList();
1013
MediaControlElement::defaultEventHandler(event);
1017
const AtomicString& MediaControlClosedCaptionsTrackListElement::shadowPseudoId() const
1019
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-closed-captions-track-list", AtomicString::ConstructFromLiteral));
1023
void MediaControlClosedCaptionsTrackListElement::updateDisplay()
1025
#if ENABLE(VIDEO_TRACK)
1026
DEFINE_STATIC_LOCAL(AtomicString, selectedClassValue, ("selected", AtomicString::ConstructFromLiteral));
1028
if (!mediaController()->hasClosedCaptions())
1031
HTMLMediaElement* mediaElement = toParentMediaElement(this);
1035
TextTrackList* trackList = mediaElement->textTracks();
1037
if (!trackList || !trackList->length())
1040
bool captionsVisible = mediaElement->closedCaptionsVisible();
1041
for (unsigned i = 0, length = menuItems.size(); i < length; ++i) {
1042
RefPtr<Element> trackItem = menuItems[i];
1043
int trackIndex = trackListIndexForElement(trackItem.get());
1044
if (trackIndex != textTracksIndexNotFound) {
1045
if (trackIndex == HTMLMediaElement::textTracksOffIndex()) {
1046
if (captionsVisible)
1047
trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
1049
trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
1051
TextTrack* track = trackList->item(trackIndex);
1054
if (track->mode() == TextTrack::showingKeyword())
1055
trackItem->classList()->add(selectedClassValue, ASSERT_NO_EXCEPTION);
1057
trackItem->classList()->remove(selectedClassValue, ASSERT_NO_EXCEPTION);
1064
void MediaControlClosedCaptionsTrackListElement::resetTrackListMenu()
1066
#if ENABLE(VIDEO_TRACK)
1067
// Remove any existing content.
1071
if (!mediaController()->hasClosedCaptions())
1074
HTMLMediaElement* mediaElement = toParentMediaElement(this);
1078
TextTrackList* trackList = mediaElement->textTracks();
1080
if (!trackList || !trackList->length())
1083
Document* doc = document();
1085
RefPtr<Element> captionsSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
1086
RefPtr<Element> captionsHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
1087
captionsHeader->appendChild(doc->createTextNode("Closed Captions"));
1088
captionsSection->appendChild(captionsHeader);
1089
RefPtr<Element> captionsList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
1091
RefPtr<Element> subtitlesSection = doc->createElement(sectionTag, ASSERT_NO_EXCEPTION);
1092
RefPtr<Element> subtitlesHeader = doc->createElement(h3Tag, ASSERT_NO_EXCEPTION);
1093
subtitlesHeader->appendChild(doc->createTextNode("Subtitles"));
1094
subtitlesSection->appendChild(subtitlesHeader);
1095
RefPtr<Element> subtitlesList = doc->createElement(ulTag, ASSERT_NO_EXCEPTION);
1097
RefPtr<Element> trackItem;
1099
trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
1100
trackItem->appendChild(doc->createTextNode("Off"));
1101
trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION);
1102
captionsList->appendChild(trackItem);
1103
menuItems.append(trackItem);
1105
trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
1106
trackItem->appendChild(doc->createTextNode("Off"));
1107
trackItem->setAttribute(trackIndexAttributeName(), textTracksOffAttrValue, ASSERT_NO_EXCEPTION);
1108
subtitlesList->appendChild(trackItem);
1109
menuItems.append(trackItem);
1111
bool hasCaptions = false;
1112
bool hasSubtitles = false;
1114
for (unsigned i = 0, length = trackList->length(); i < length; ++i) {
1115
TextTrack* track = trackList->item(i);
1116
trackItem = doc->createElement(liTag, ASSERT_NO_EXCEPTION);
1118
// Add a custom attribute to the <li> element which will allow
1119
// us to easily associate the user tapping here with the
1120
// track. Since this list is rebuilt if the tracks change, we
1121
// should always be in sync.
1122
trackItem->setAttribute(trackIndexAttributeName(), String::number(i), ASSERT_NO_EXCEPTION);
1124
AtomicString labelText = track->label();
1125
if (labelText.isNull() || labelText.isEmpty())
1126
labelText = displayNameForLanguageLocale(track->language());
1127
if (labelText.isNull() || labelText.isEmpty())
1128
labelText = "No Label";
1130
if (track->kind() == track->captionsKeyword()) {
1132
captionsList->appendChild(trackItem);
1134
if (track->kind() == track->subtitlesKeyword()) {
1135
hasSubtitles = true;
1136
subtitlesList->appendChild(trackItem);
1138
trackItem->appendChild(doc->createTextNode(labelText));
1139
menuItems.append(trackItem);
1142
captionsSection->appendChild(captionsList);
1143
subtitlesSection->appendChild(subtitlesList);
1146
appendChild(captionsSection);
1148
appendChild(subtitlesSection);
1154
// ----------------------------
1156
MediaControlTimelineElement::MediaControlTimelineElement(Document* document, MediaControls* controls)
1157
: MediaControlInputElement(document, MediaSlider)
1158
, m_controls(controls)
1162
PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(Document* document, MediaControls* controls)
1166
RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(document, controls));
1167
timeline->createShadowSubtree();
1168
timeline->setType("range");
1169
timeline->setAttribute(precisionAttr, "float");
1170
return timeline.release();
1173
void MediaControlTimelineElement::defaultEventHandler(Event* event)
1175
// Left button is 0. Rejects mouse events not from left button.
1176
if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
1182
if (event->type() == eventNames().mousedownEvent)
1183
mediaController()->beginScrubbing();
1185
if (event->type() == eventNames().mouseupEvent)
1186
mediaController()->endScrubbing();
1188
MediaControlInputElement::defaultEventHandler(event);
1190
if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
1193
float time = narrowPrecisionToFloat(value().toDouble());
1194
if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) {
1196
mediaController()->setCurrentTime(time, ec);
1199
RenderSlider* slider = toRenderSlider(renderer());
1200
if (slider && slider->inDragMode())
1201
m_controls->updateCurrentTimeDisplay();
1204
bool MediaControlTimelineElement::willRespondToMouseClickEvents()
1212
void MediaControlTimelineElement::setPosition(float currentTime)
1214
setValue(String::number(currentTime));
1217
void MediaControlTimelineElement::setDuration(float duration)
1219
setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
1223
const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
1225
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline", AtomicString::ConstructFromLiteral));
1229
// ----------------------------
1231
inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
1232
: MediaControlInputElement(document, MediaVolumeSlider)
1233
, m_clearMutedOnUserInteraction(false)
1237
PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(Document* document)
1239
RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(document));
1240
slider->createShadowSubtree();
1241
slider->setType("range");
1242
slider->setAttribute(precisionAttr, "float");
1243
slider->setAttribute(maxAttr, "1");
1244
return slider.release();
1247
void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
1249
// Left button is 0. Rejects mouse events not from left button.
1250
if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
1256
MediaControlInputElement::defaultEventHandler(event);
1258
if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
1261
float volume = narrowPrecisionToFloat(value().toDouble());
1262
if (volume != mediaController()->volume()) {
1263
ExceptionCode ec = 0;
1264
mediaController()->setVolume(volume, ec);
1267
if (m_clearMutedOnUserInteraction)
1268
mediaController()->setMuted(false);
1271
bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
1276
return MediaControlInputElement::willRespondToMouseMoveEvents();
1279
bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
1284
return MediaControlInputElement::willRespondToMouseClickEvents();
1287
void MediaControlVolumeSliderElement::setVolume(float volume)
1289
if (value().toFloat() != volume)
1290
setValue(String::number(volume));
1293
void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
1295
m_clearMutedOnUserInteraction = clearMute;
1298
const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
1300
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider", AtomicString::ConstructFromLiteral));
1304
// ----------------------------
1306
inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(Document* document)
1307
: MediaControlVolumeSliderElement(document)
1311
PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(Document* document)
1313
RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(document));
1314
slider->createShadowSubtree();
1315
slider->setType("range");
1316
slider->setAttribute(precisionAttr, "float");
1317
slider->setAttribute(maxAttr, "1");
1318
return slider.release();
1321
const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
1323
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider", AtomicString::ConstructFromLiteral));
1327
// ----------------------------
1329
inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, MediaControls*)
1330
: MediaControlInputElement(document, MediaEnterFullscreenButton)
1334
PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(Document* document, MediaControls* controls)
1338
RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(document, controls));
1339
button->createShadowSubtree();
1340
button->setType("button");
1342
return button.release();
1345
void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
1347
if (event->type() == eventNames().clickEvent) {
1348
#if ENABLE(FULLSCREEN_API)
1349
// Only use the new full screen API if the fullScreenEnabled setting has
1350
// been explicitly enabled. Otherwise, use the old fullscreen API. This
1351
// allows apps which embed a WebView to retain the existing full screen
1352
// video implementation without requiring them to implement their own full
1354
if (document()->settings() && document()->settings()->fullScreenEnabled()) {
1355
if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this))
1356
document()->webkitCancelFullScreen();
1358
document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
1361
mediaController()->enterFullscreen();
1362
event->setDefaultHandled();
1364
HTMLInputElement::defaultEventHandler(event);
1367
const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
1369
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button", AtomicString::ConstructFromLiteral));
1373
void MediaControlFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
1375
setDisplayType(isFullscreen ? MediaExitFullscreenButton : MediaEnterFullscreenButton);
1378
// ----------------------------
1380
inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(Document* document)
1381
: MediaControlInputElement(document, MediaUnMuteButton)
1385
PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(Document* document)
1387
RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(document));
1388
button->createShadowSubtree();
1389
button->setType("button");
1390
return button.release();
1393
void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
1395
if (event->type() == eventNames().clickEvent) {
1396
ExceptionCode code = 0;
1397
mediaController()->setVolume(0, code);
1398
event->setDefaultHandled();
1400
HTMLInputElement::defaultEventHandler(event);
1403
const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
1405
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button", AtomicString::ConstructFromLiteral));
1409
// ----------------------------
1411
inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(Document* document)
1412
: MediaControlInputElement(document, MediaMuteButton)
1416
PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(Document* document)
1418
RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(document));
1419
button->createShadowSubtree();
1420
button->setType("button");
1421
return button.release();
1424
void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
1426
if (event->type() == eventNames().clickEvent) {
1427
ExceptionCode code = 0;
1428
mediaController()->setVolume(1, code);
1429
event->setDefaultHandled();
1431
HTMLInputElement::defaultEventHandler(event);
1434
const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
1436
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button", AtomicString::ConstructFromLiteral));
1440
// ----------------------------
1442
class RenderMediaControlTimeDisplay : public RenderDeprecatedFlexibleBox {
1444
RenderMediaControlTimeDisplay(Node*);
1447
virtual void layout();
1450
RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
1451
: RenderDeprecatedFlexibleBox(node)
1455
// We want the timeline slider to be at least 100 pixels wide.
1456
// FIXME: Eliminate hard-coded widths altogether.
1457
static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
1459
void RenderMediaControlTimeDisplay::layout()
1461
RenderDeprecatedFlexibleBox::layout();
1462
RenderBox* timelineContainerBox = parentBox();
1463
while (timelineContainerBox && timelineContainerBox->isAnonymous())
1464
timelineContainerBox = timelineContainerBox->parentBox();
1466
if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
1470
inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document)
1471
: MediaControlElement(document)
1476
void MediaControlTimeDisplayElement::setCurrentValue(float time)
1478
m_currentValue = time;
1481
RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
1483
return new (arena) RenderMediaControlTimeDisplay(this);
1486
// ----------------------------
1488
PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(Document* document)
1490
return adoptRef(new MediaControlTimeRemainingDisplayElement(document));
1493
MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(Document* document)
1494
: MediaControlTimeDisplayElement(document)
1498
MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const
1500
return MediaTimeRemainingDisplay;
1503
const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
1505
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display", AtomicString::ConstructFromLiteral));
1509
// ----------------------------
1511
PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(Document* document)
1513
return adoptRef(new MediaControlCurrentTimeDisplayElement(document));
1516
MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(Document* document)
1517
: MediaControlTimeDisplayElement(document)
1521
MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const
1523
return MediaCurrentTimeDisplay;
1526
const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
1528
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display", AtomicString::ConstructFromLiteral));
1532
// ----------------------------
1534
#if ENABLE(VIDEO_TRACK)
1536
class RenderTextTrackContainerElement : public RenderBlock {
1538
RenderTextTrackContainerElement(Node*);
1541
virtual void layout();
1544
RenderTextTrackContainerElement::RenderTextTrackContainerElement(Node* node)
1549
void RenderTextTrackContainerElement::layout()
1551
RenderBlock::layout();
1552
if (style()->display() == NONE)
1555
ASSERT(mediaControlElementType(node()) == MediaTextTrackDisplayContainer);
1557
LayoutStateDisabler layoutStateDisabler(view());
1558
static_cast<MediaControlTextTrackContainerElement*>(node())->updateSizes();
1561
inline MediaControlTextTrackContainerElement::MediaControlTextTrackContainerElement(Document* document)
1562
: MediaControlElement(document)
1567
PassRefPtr<MediaControlTextTrackContainerElement> MediaControlTextTrackContainerElement::create(Document* document)
1569
RefPtr<MediaControlTextTrackContainerElement> element = adoptRef(new MediaControlTextTrackContainerElement(document));
1571
return element.release();
1574
RenderObject* MediaControlTextTrackContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
1576
return new (arena) RenderTextTrackContainerElement(this);
1579
const AtomicString& MediaControlTextTrackContainerElement::shadowPseudoId() const
1581
DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-text-track-container", AtomicString::ConstructFromLiteral));
1585
void MediaControlTextTrackContainerElement::updateDisplay()
1587
HTMLMediaElement* mediaElement = toParentMediaElement(this);
1589
// 1. If the media element is an audio element, or is another playback
1590
// mechanism with no rendering area, abort these steps. There is nothing to
1592
if (!mediaElement->isVideo())
1595
// 2. Let video be the media element or other playback mechanism.
1596
HTMLVideoElement* video = static_cast<HTMLVideoElement*>(mediaElement);
1598
// 3. Let output be an empty list of absolutely positioned CSS block boxes.
1599
Vector<RefPtr<HTMLDivElement> > output;
1601
// 4. If the user agent is exposing a user interface for video, add to
1602
// output one or more completely transparent positioned CSS block boxes that
1603
// cover the same region as the user interface.
1605
// 5. If the last time these rules were run, the user agent was not exposing
1606
// a user interface for video, but now it is, let reset be true. Otherwise,
1607
// let reset be false.
1609
// There is nothing to be done explicitly for 4th and 5th steps, as
1610
// everything is handled through CSS. The caption box is on top of the
1611
// controls box, in a container set with the -webkit-box display property.
1613
// 6. Let tracks be the subset of video's list of text tracks that have as
1614
// their rules for updating the text track rendering these rules for
1615
// updating the display of WebVTT text tracks, and whose text track mode is
1616
// showing or showing by default.
1617
// 7. Let cues be an empty list of text track cues.
1618
// 8. For each track track in tracks, append to cues all the cues from
1619
// track's list of cues that have their text track cue active flag set.
1620
CueList activeCues = video->currentlyActiveCues();
1622
// 9. If reset is false, then, for each text track cue cue in cues: if cue's
1623
// text track cue display state has a set of CSS boxes, then add those boxes
1624
// to output, and remove cue from cues.
1626
// There is nothing explicitly to be done here, as all the caching occurs
1627
// within the TextTrackCue instance itself. If parameters of the cue change,
1628
// the display tree is cleared.
1630
// 10. For each text track cue cue in cues that has not yet had
1631
// corresponding CSS boxes added to output, in text track cue order, run the
1632
// following substeps:
1633
for (size_t i = 0; i < activeCues.size(); ++i) {
1634
TextTrackCue* cue = activeCues[i].data();
1636
ASSERT(cue->isActive());
1637
if (!cue->track() || !cue->track()->isRendered())
1640
RefPtr<TextTrackCueBox> displayBox = cue->getDisplayTree();
1642
if (displayBox->hasChildNodes() && !contains(static_cast<Node*>(displayBox.get())))
1643
// Note: the display tree of a cue is removed when the active flag of the cue is unset.
1644
appendChild(displayBox, ASSERT_NO_EXCEPTION, false);
1647
// 11. Return output.
1648
hasChildNodes() ? show() : hide();
1651
void MediaControlTextTrackContainerElement::updateSizes()
1653
HTMLMediaElement* mediaElement = toParentMediaElement(this);
1654
if (!mediaElement || !mediaElement->renderer() || !mediaElement->renderer()->isVideo())
1657
if (!document()->page())
1660
IntRect videoBox = toRenderVideo(mediaElement->renderer())->videoBox();
1662
float fontSize = videoBox.size().height() * (document()->page()->group().captionFontSizeScale());
1663
if (fontSize != m_fontSize) {
1664
m_fontSize = fontSize;
1665
setInlineStyleProperty(CSSPropertyFontSize, String::number(fontSize) + "px");
1669
#endif // ENABLE(VIDEO_TRACK)
1671
// ----------------------------
1673
} // namespace WebCore
1675
#endif // ENABLE(VIDEO)