• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008, 2009, 2010 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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.
16  *
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.
27  */
28 
29 #include "config.h"
30 
31 #if ENABLE(VIDEO)
32 
33 #include "MediaControlElements.h"
34 
35 #include "CSSStyleSelector.h"
36 #include "EventNames.h"
37 #include "FloatConversion.h"
38 #include "Frame.h"
39 #include "HTMLNames.h"
40 #include "LocalizedStrings.h"
41 #include "MediaControls.h"
42 #include "MouseEvent.h"
43 #include "Page.h"
44 #include "RenderFlexibleBox.h"
45 #include "RenderMedia.h"
46 #include "RenderSlider.h"
47 #include "RenderTheme.h"
48 #include "RenderView.h"
49 #include "Settings.h"
50 
51 namespace WebCore {
52 
53 using namespace HTMLNames;
54 
toParentMediaElement(RenderObject * o)55 HTMLMediaElement* toParentMediaElement(RenderObject* o)
56 {
57     Node* node = o->node();
58     Node* mediaNode = node ? node->shadowAncestorNode() : 0;
59     if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
60         return 0;
61 
62     return static_cast<HTMLMediaElement*>(mediaNode);
63 }
64 
65 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
66 static const float cSeekRepeatDelay = 0.1f;
67 static const float cStepTime = 0.07f;
68 static const float cSeekTime = 0.2f;
69 
70 // ----------------------------
71 
MediaControlElement(HTMLMediaElement * mediaElement)72 MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement)
73     : HTMLDivElement(divTag, mediaElement->document())
74     , m_mediaElement(mediaElement)
75 {
76 }
77 
displayString()78 static const String& displayString()
79 {
80     DEFINE_STATIC_LOCAL(String, s, ("display"));
81     return s;
82 }
83 
show()84 void MediaControlElement::show()
85 {
86     ExceptionCode ec;
87     // FIXME: Make more efficient <http://webkit.org/b/58157>
88     style()->removeProperty(displayString(), ec);
89 }
90 
hide()91 void MediaControlElement::hide()
92 {
93     ExceptionCode ec;
94     // FIXME: Make more efficient <http://webkit.org/b/58157>
95     DEFINE_STATIC_LOCAL(String, none, ("none"));
96     style()->setProperty(displayString(), none, ec);
97 }
98 
99 // ----------------------------
100 
MediaControlPanelElement(HTMLMediaElement * mediaElement)101 inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement)
102     : MediaControlElement(mediaElement)
103 {
104 }
105 
create(HTMLMediaElement * mediaElement)106 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement)
107 {
108     return adoptRef(new MediaControlPanelElement(mediaElement));
109 }
110 
displayType() const111 MediaControlElementType MediaControlPanelElement::displayType() const
112 {
113     return MediaControlsPanel;
114 }
115 
shadowPseudoId() const116 const AtomicString& MediaControlPanelElement::shadowPseudoId() const
117 {
118     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel"));
119     return id;
120 }
121 
122 // ----------------------------
123 
MediaControlTimelineContainerElement(HTMLMediaElement * mediaElement)124 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement)
125     : MediaControlElement(mediaElement)
126 {
127 }
128 
create(HTMLMediaElement * mediaElement)129 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement)
130 {
131     RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(mediaElement));
132     element->hide();
133     return element.release();
134 }
135 
displayType() const136 MediaControlElementType MediaControlTimelineContainerElement::displayType() const
137 {
138     return MediaTimelineContainer;
139 }
140 
shadowPseudoId() const141 const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const
142 {
143     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container"));
144     return id;
145 }
146 
147 // ----------------------------
148 
149 class RenderMediaVolumeSliderContainer : public RenderBlock {
150 public:
151     RenderMediaVolumeSliderContainer(Node*);
152 
153 private:
154     virtual void layout();
155 };
156 
RenderMediaVolumeSliderContainer(Node * node)157 RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node)
158     : RenderBlock(node)
159 {
160 }
161 
layout()162 void RenderMediaVolumeSliderContainer::layout()
163 {
164     RenderBlock::layout();
165     if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox())
166         return;
167 
168     RenderBox* buttonBox = toRenderBox(previousSibling());
169 
170     if (view())
171         view()->disableLayoutState();
172 
173     IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height()));
174     setX(offset.x() + buttonBox->offsetLeft());
175     setY(offset.y() + buttonBox->offsetTop());
176 
177     if (view())
178         view()->enableLayoutState();
179 }
180 
MediaControlVolumeSliderContainerElement(HTMLMediaElement * mediaElement)181 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement)
182     : MediaControlElement(mediaElement)
183 {
184 }
185 
create(HTMLMediaElement * mediaElement)186 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement)
187 {
188     RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement));
189     element->hide();
190     return element.release();
191 }
192 
createRenderer(RenderArena * arena,RenderStyle *)193 RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*)
194 {
195     return new (arena) RenderMediaVolumeSliderContainer(this);
196 }
197 
defaultEventHandler(Event * event)198 void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event)
199 {
200     if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent)
201         return;
202 
203     // Poor man's mouseleave event detection.
204     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
205     if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode())
206         return;
207 
208     if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode()))
209         return;
210 
211     hide();
212 }
213 
214 
displayType() const215 MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const
216 {
217     return MediaVolumeSliderContainer;
218 }
219 
shadowPseudoId() const220 const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const
221 {
222     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container"));
223     return id;
224 }
225 
226 // ----------------------------
227 
MediaControlStatusDisplayElement(HTMLMediaElement * mediaElement)228 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement)
229     : MediaControlElement(mediaElement)
230     , m_stateBeingDisplayed(Nothing)
231 {
232 }
233 
create(HTMLMediaElement * mediaElement)234 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement)
235 {
236     RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(mediaElement));
237     element->hide();
238     return element.release();
239 }
240 
update()241 void MediaControlStatusDisplayElement::update()
242 {
243     // Get the new state that we'll have to display.
244     StateBeingDisplayed newStateToDisplay = Nothing;
245 
246     if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty())
247         newStateToDisplay = Loading;
248     else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream)
249         newStateToDisplay = LiveBroadcast;
250 
251     if (newStateToDisplay == m_stateBeingDisplayed)
252         return;
253 
254     ExceptionCode e;
255 
256     if (m_stateBeingDisplayed == Nothing)
257         show();
258     else if (newStateToDisplay == Nothing)
259         hide();
260 
261     m_stateBeingDisplayed = newStateToDisplay;
262 
263     switch (m_stateBeingDisplayed) {
264     case Nothing:
265         setInnerText("", e);
266         break;
267     case Loading:
268         setInnerText(mediaElementLoadingStateText(), e);
269         break;
270     case LiveBroadcast:
271         setInnerText(mediaElementLiveBroadcastStateText(), e);
272         break;
273     }
274 }
275 
displayType() const276 MediaControlElementType MediaControlStatusDisplayElement::displayType() const
277 {
278     return MediaStatusDisplay;
279 }
280 
shadowPseudoId() const281 const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const
282 {
283     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display"));
284     return id;
285 }
286 
287 // ----------------------------
288 
MediaControlInputElement(HTMLMediaElement * mediaElement,MediaControlElementType displayType)289 MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
290     : HTMLInputElement(inputTag, mediaElement->document(), 0, false)
291     , m_mediaElement(mediaElement)
292     , m_displayType(displayType)
293 {
294 }
295 
show()296 void MediaControlInputElement::show()
297 {
298     ExceptionCode ec;
299     style()->removeProperty(displayString(), ec);
300 }
301 
hide()302 void MediaControlInputElement::hide()
303 {
304     ExceptionCode ec;
305     DEFINE_STATIC_LOCAL(String, none, ("none"));
306     style()->setProperty(displayString(), none, ec);
307 }
308 
309 
setDisplayType(MediaControlElementType displayType)310 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
311 {
312     if (displayType == m_displayType)
313         return;
314 
315     m_displayType = displayType;
316     if (RenderObject* object = renderer())
317         object->repaint();
318 }
319 
320 // ----------------------------
321 
MediaControlMuteButtonElement(HTMLMediaElement * mediaElement,MediaControlElementType displayType)322 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
323     : MediaControlInputElement(mediaElement, displayType)
324 {
325 }
326 
defaultEventHandler(Event * event)327 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
328 {
329     if (event->type() == eventNames().clickEvent) {
330         mediaElement()->setMuted(!mediaElement()->muted());
331         event->setDefaultHandled();
332     }
333 
334     HTMLInputElement::defaultEventHandler(event);
335 }
336 
changedMute()337 void MediaControlMuteButtonElement::changedMute()
338 {
339     updateDisplayType();
340 }
341 
updateDisplayType()342 void MediaControlMuteButtonElement::updateDisplayType()
343 {
344     setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton);
345 }
346 
347 // ----------------------------
348 
MediaControlPanelMuteButtonElement(HTMLMediaElement * mediaElement,MediaControls * controls)349 inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls)
350     : MediaControlMuteButtonElement(mediaElement, MediaMuteButton)
351     , m_controls(controls)
352 {
353 }
354 
create(HTMLMediaElement * mediaElement,MediaControls * controls)355 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
356 {
357     ASSERT(controls);
358 
359     RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement, controls));
360     button->setType("button");
361     return button.release();
362 }
363 
defaultEventHandler(Event * event)364 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event)
365 {
366     if (event->type() == eventNames().mouseoverEvent)
367         m_controls->showVolumeSlider();
368 
369     MediaControlMuteButtonElement::defaultEventHandler(event);
370 }
371 
shadowPseudoId() const372 const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const
373 {
374     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button"));
375     return id;
376 }
377 
378 // ----------------------------
379 
MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement * mediaElement)380 inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement)
381     : MediaControlMuteButtonElement(mediaElement, MediaMuteButton)
382 {
383 }
384 
create(HTMLMediaElement * mediaElement)385 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement)
386 {
387     RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement));
388     button->setType("button");
389     return button.release();
390 }
391 
shadowPseudoId() const392 const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const
393 {
394     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button"));
395     return id;
396 }
397 
398 // ----------------------------
399 
MediaControlPlayButtonElement(HTMLMediaElement * mediaElement)400 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement)
401     : MediaControlInputElement(mediaElement, MediaPlayButton)
402 {
403 }
404 
create(HTMLMediaElement * mediaElement)405 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement)
406 {
407     RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement));
408     button->setType("button");
409     return button.release();
410 }
411 
defaultEventHandler(Event * event)412 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
413 {
414     if (event->type() == eventNames().clickEvent) {
415         mediaElement()->togglePlayState();
416         updateDisplayType();
417         event->setDefaultHandled();
418     }
419     HTMLInputElement::defaultEventHandler(event);
420 }
421 
updateDisplayType()422 void MediaControlPlayButtonElement::updateDisplayType()
423 {
424     setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton);
425 }
426 
shadowPseudoId() const427 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const
428 {
429     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button"));
430     return id;
431 }
432 
433 // ----------------------------
434 
MediaControlSeekButtonElement(HTMLMediaElement * mediaElement,MediaControlElementType displayType)435 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType)
436     : MediaControlInputElement(mediaElement, displayType)
437     , m_seeking(false)
438     , m_capturing(false)
439     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
440 {
441 }
442 
defaultEventHandler(Event * event)443 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
444 {
445     if (event->type() == eventNames().mousedownEvent) {
446         if (Frame* frame = document()->frame()) {
447             m_capturing = true;
448             frame->eventHandler()->setCapturingMouseEventsNode(this);
449         }
450         mediaElement()->pause(event->fromUserGesture());
451         m_seekTimer.startRepeating(cSeekRepeatDelay);
452         event->setDefaultHandled();
453     } else if (event->type() == eventNames().mouseupEvent) {
454         if (m_capturing)
455             if (Frame* frame = document()->frame()) {
456                 m_capturing = false;
457                 frame->eventHandler()->setCapturingMouseEventsNode(0);
458             }
459         ExceptionCode ec;
460         if (m_seeking || m_seekTimer.isActive()) {
461             if (!m_seeking) {
462                 float stepTime = isForwardButton() ? cStepTime : -cStepTime;
463                 mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec);
464             }
465             m_seekTimer.stop();
466             m_seeking = false;
467             event->setDefaultHandled();
468         }
469     }
470     HTMLInputElement::defaultEventHandler(event);
471 }
472 
seekTimerFired(Timer<MediaControlSeekButtonElement> *)473 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
474 {
475     ExceptionCode ec;
476     m_seeking = true;
477     float seekTime = isForwardButton() ? cSeekTime : -cSeekTime;
478     mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec);
479 }
480 
detach()481 void MediaControlSeekButtonElement::detach()
482 {
483     if (m_capturing) {
484         if (Frame* frame = document()->frame())
485             frame->eventHandler()->setCapturingMouseEventsNode(0);
486     }
487     MediaControlInputElement::detach();
488 }
489 
490 // ----------------------------
491 
MediaControlSeekForwardButtonElement(HTMLMediaElement * mediaElement)492 inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement)
493     : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton)
494 {
495 }
496 
create(HTMLMediaElement * mediaElement)497 PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement)
498 {
499     RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement));
500     button->setType("button");
501     return button.release();
502 }
503 
shadowPseudoId() const504 const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const
505 {
506     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button"));
507     return id;
508 }
509 
510 // ----------------------------
511 
MediaControlSeekBackButtonElement(HTMLMediaElement * mediaElement)512 inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement)
513     : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton)
514 {
515 }
516 
create(HTMLMediaElement * mediaElement)517 PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement)
518 {
519     RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement));
520     button->setType("button");
521     return button.release();
522 }
523 
shadowPseudoId() const524 const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const
525 {
526     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button"));
527     return id;
528 }
529 
530 // ----------------------------
531 
MediaControlRewindButtonElement(HTMLMediaElement * element)532 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element)
533     : MediaControlInputElement(element, MediaRewindButton)
534 {
535 }
536 
create(HTMLMediaElement * mediaElement)537 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement)
538 {
539     RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement));
540     button->setType("button");
541     return button.release();
542 }
543 
defaultEventHandler(Event * event)544 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
545 {
546     if (event->type() == eventNames().clickEvent) {
547         mediaElement()->rewind(30);
548         event->setDefaultHandled();
549     }
550     HTMLInputElement::defaultEventHandler(event);
551 }
552 
shadowPseudoId() const553 const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const
554 {
555     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button"));
556     return id;
557 }
558 
559 // ----------------------------
560 
MediaControlReturnToRealtimeButtonElement(HTMLMediaElement * mediaElement)561 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement)
562     : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton)
563 {
564 }
565 
create(HTMLMediaElement * mediaElement)566 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement)
567 {
568     RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement));
569     button->setType("button");
570     button->hide();
571     return button.release();
572 }
573 
defaultEventHandler(Event * event)574 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
575 {
576     if (event->type() == eventNames().clickEvent) {
577         mediaElement()->returnToRealtime();
578         event->setDefaultHandled();
579     }
580     HTMLInputElement::defaultEventHandler(event);
581 }
582 
shadowPseudoId() const583 const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const
584 {
585     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button"));
586     return id;
587 }
588 
589 // ----------------------------
590 
MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement * mediaElement)591 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement)
592     : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton)
593 {
594 }
595 
create(HTMLMediaElement * mediaElement)596 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement)
597 {
598     RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement));
599     button->setType("button");
600     button->hide();
601     return button.release();
602 }
603 
defaultEventHandler(Event * event)604 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
605 {
606     if (event->type() == eventNames().clickEvent) {
607         mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible());
608         setChecked(mediaElement()->closedCaptionsVisible());
609         updateDisplayType();
610         event->setDefaultHandled();
611     }
612 
613     HTMLInputElement::defaultEventHandler(event);
614 }
615 
updateDisplayType()616 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
617 {
618     setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
619 }
620 
shadowPseudoId() const621 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const
622 {
623     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button"));
624     return id;
625 }
626 
627 // ----------------------------
628 
MediaControlTimelineElement(HTMLMediaElement * mediaElement,MediaControls * controls)629 MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement, MediaControls* controls)
630     : MediaControlInputElement(mediaElement, MediaSlider)
631     , m_controls(controls)
632 {
633 }
634 
create(HTMLMediaElement * mediaElement,MediaControls * controls)635 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
636 {
637     ASSERT(controls);
638 
639     RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement, controls));
640     timeline->setType("range");
641     timeline->setAttribute(precisionAttr, "float");
642     return timeline.release();
643 }
644 
defaultEventHandler(Event * event)645 void MediaControlTimelineElement::defaultEventHandler(Event* event)
646 {
647     // Left button is 0. Rejects mouse events not from left button.
648     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
649         return;
650 
651     if (!attached())
652         return;
653 
654     if (event->type() == eventNames().mousedownEvent)
655         mediaElement()->beginScrubbing();
656 
657 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
658     if (event->type() == eventNames().touchstartEvent)
659         mediaElement()->beginScrubbing();
660 #endif
661 
662     MediaControlInputElement::defaultEventHandler(event);
663 
664     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
665         return;
666 
667 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
668     if (event->type() == eventNames().touchmoveEvent || event->type() == eventNames().touchcancelEvent)
669         return;
670 #endif
671 
672     float time = narrowPrecisionToFloat(value().toDouble());
673     if (time != mediaElement()->currentTime()) {
674         // FIXME: This is fired 3 times on every click. We should not be doing that <http:/webkit.org/b/58160>.
675         ExceptionCode ec;
676         mediaElement()->setCurrentTime(time, ec);
677     }
678 
679     RenderSlider* slider = toRenderSlider(renderer());
680     if (slider && slider->inDragMode())
681         m_controls->updateTimeDisplay();
682 
683     if (event->type() == eventNames().mouseupEvent)
684         mediaElement()->endScrubbing();
685 
686 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
687     if (event->type() == eventNames().touchendEvent)
688         mediaElement()->endScrubbing();
689 #endif
690 }
691 
setPosition(float currentTime)692 void MediaControlTimelineElement::setPosition(float currentTime)
693 {
694     setValue(String::number(currentTime));
695 }
696 
setDuration(float duration)697 void MediaControlTimelineElement::setDuration(float duration)
698 {
699     setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
700 }
701 
702 
shadowPseudoId() const703 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const
704 {
705     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline"));
706     return id;
707 }
708 
709 // ----------------------------
710 
MediaControlVolumeSliderElement(HTMLMediaElement * mediaElement)711 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement)
712     : MediaControlInputElement(mediaElement, MediaVolumeSlider)
713 {
714 }
715 
create(HTMLMediaElement * mediaElement)716 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement)
717 {
718     RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement));
719     slider->setType("range");
720     slider->setAttribute(precisionAttr, "float");
721     slider->setAttribute(maxAttr, "1");
722     slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
723     return slider.release();
724 }
725 
defaultEventHandler(Event * event)726 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
727 {
728     // Left button is 0. Rejects mouse events not from left button.
729     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
730         return;
731 
732     if (!attached())
733         return;
734 
735     MediaControlInputElement::defaultEventHandler(event);
736 
737     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
738         return;
739 
740     float volume = narrowPrecisionToFloat(value().toDouble());
741     if (volume != mediaElement()->volume()) {
742         ExceptionCode ec = 0;
743         mediaElement()->setVolume(volume, ec);
744         ASSERT(!ec);
745     }
746 }
747 
setVolume(float volume)748 void MediaControlVolumeSliderElement::setVolume(float volume)
749 {
750     if (value().toFloat() != volume)
751         setValue(String::number(volume));
752 }
753 
shadowPseudoId() const754 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const
755 {
756     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider"));
757     return id;
758 }
759 
760 // ----------------------------
761 
MediaControlFullscreenVolumeSliderElement(HTMLMediaElement * mediaElement)762 inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement)
763     : MediaControlVolumeSliderElement(mediaElement)
764 {
765 }
766 
create(HTMLMediaElement * mediaElement)767 PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement)
768 {
769     RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement));
770     slider->setType("range");
771     slider->setAttribute(precisionAttr, "float");
772     slider->setAttribute(maxAttr, "1");
773     slider->setAttribute(valueAttr, String::number(mediaElement->volume()));
774     return slider.release();
775 }
776 
shadowPseudoId() const777 const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const
778 {
779     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider"));
780     return id;
781 }
782 
783 // ----------------------------
784 
MediaControlFullscreenButtonElement(HTMLMediaElement * mediaElement,MediaControls * controls)785 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls)
786     : MediaControlInputElement(mediaElement, MediaFullscreenButton)
787     , m_controls(controls)
788 {
789 }
790 
create(HTMLMediaElement * mediaElement,MediaControls * controls)791 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls)
792 {
793     ASSERT(controls);
794 
795     RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement, controls));
796     button->setType("button");
797     button->hide();
798     return button.release();
799 }
800 
defaultEventHandler(Event * event)801 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
802 {
803     if (event->type() == eventNames().clickEvent) {
804 #if ENABLE(FULLSCREEN_API)
805         // Only use the new full screen API if the fullScreenEnabled setting has
806         // been explicitly enabled. Otherwise, use the old fullscreen API. This
807         // allows apps which embed a WebView to retain the existing full screen
808         // video implementation without requiring them to implement their own full
809         // screen behavior.
810         if (document()->settings() && document()->settings()->fullScreenEnabled()) {
811             if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement()) {
812                 document()->webkitCancelFullScreen();
813                 m_controls->exitedFullscreen();
814             } else {
815                 mediaElement()->webkitRequestFullScreen(0);
816                 m_controls->enteredFullscreen();
817             }
818         } else
819 #endif
820             mediaElement()->enterFullscreen();
821         event->setDefaultHandled();
822     }
823     HTMLInputElement::defaultEventHandler(event);
824 }
825 
shadowPseudoId() const826 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const
827 {
828     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button"));
829     return id;
830 }
831 
832 // ----------------------------
833 
MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement * mediaElement)834 inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement)
835     : MediaControlInputElement(mediaElement, MediaUnMuteButton)
836 {
837 }
838 
create(HTMLMediaElement * mediaElement)839 PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement)
840 {
841     RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement));
842     button->setType("button");
843     return button.release();
844 }
845 
defaultEventHandler(Event * event)846 void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event)
847 {
848     if (event->type() == eventNames().clickEvent) {
849         ExceptionCode code = 0;
850         mediaElement()->setVolume(0, code);
851         event->setDefaultHandled();
852     }
853     HTMLInputElement::defaultEventHandler(event);
854 }
855 
shadowPseudoId() const856 const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const
857 {
858     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button"));
859     return id;
860 }
861 
862 // ----------------------------
863 
MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement * mediaElement)864 inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement)
865 : MediaControlInputElement(mediaElement, MediaMuteButton)
866 {
867 }
868 
create(HTMLMediaElement * mediaElement)869 PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement)
870 {
871     RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement));
872     button->setType("button");
873     return button.release();
874 }
875 
defaultEventHandler(Event * event)876 void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event)
877 {
878     if (event->type() == eventNames().clickEvent) {
879         ExceptionCode code = 0;
880         mediaElement()->setVolume(1, code);
881         event->setDefaultHandled();
882     }
883     HTMLInputElement::defaultEventHandler(event);
884 }
885 
shadowPseudoId() const886 const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const
887 {
888     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button"));
889     return id;
890 }
891 
892 // ----------------------------
893 
894 class RenderMediaControlTimeDisplay : public RenderFlexibleBox {
895 public:
896     RenderMediaControlTimeDisplay(Node*);
897 
898 private:
899     virtual void layout();
900 };
901 
RenderMediaControlTimeDisplay(Node * node)902 RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node)
903     : RenderFlexibleBox(node)
904 {
905 }
906 
907 // We want the timeline slider to be at least 100 pixels wide.
908 // FIXME: Eliminate hard-coded widths altogether.
909 static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45;
910 
layout()911 void RenderMediaControlTimeDisplay::layout()
912 {
913     RenderFlexibleBox::layout();
914     RenderBox* timelineContainerBox = parentBox();
915     while (timelineContainerBox && timelineContainerBox->isAnonymous())
916         timelineContainerBox = timelineContainerBox->parentBox();
917 
918     if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays)
919         setWidth(0);
920 }
921 
MediaControlTimeDisplayElement(HTMLMediaElement * mediaElement)922 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement)
923     : MediaControlElement(mediaElement)
924     , m_currentValue(0)
925 {
926 }
927 
setCurrentValue(float time)928 void MediaControlTimeDisplayElement::setCurrentValue(float time)
929 {
930     m_currentValue = time;
931 }
932 
createRenderer(RenderArena * arena,RenderStyle *)933 RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*)
934 {
935     return new (arena) RenderMediaControlTimeDisplay(this);
936 }
937 
938 // ----------------------------
939 
create(HTMLMediaElement * mediaElement)940 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement)
941 {
942     return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement));
943 }
944 
MediaControlTimeRemainingDisplayElement(HTMLMediaElement * mediaElement)945 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement)
946     : MediaControlTimeDisplayElement(mediaElement)
947 {
948 }
949 
displayType() const950 MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const
951 {
952     return MediaTimeRemainingDisplay;
953 }
954 
shadowPseudoId() const955 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const
956 {
957     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display"));
958     return id;
959 }
960 
961 // ----------------------------
962 
create(HTMLMediaElement * mediaElement)963 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement)
964 {
965     return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement));
966 }
967 
MediaControlCurrentTimeDisplayElement(HTMLMediaElement * mediaElement)968 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement)
969     : MediaControlTimeDisplayElement(mediaElement)
970 {
971 }
972 
displayType() const973 MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const
974 {
975     return MediaCurrentTimeDisplay;
976 }
977 
shadowPseudoId() const978 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const
979 {
980     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display"));
981     return id;
982 }
983 
984 } // namespace WebCore
985 
986 #endif // ENABLE(VIDEO)
987