1 /*
2 * Copyright (C) 2008, 2009 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 "EventNames.h"
36 #include "FloatConversion.h"
37 #include "Frame.h"
38 #include "HTMLNames.h"
39 #include "LocalizedStrings.h"
40 #include "MouseEvent.h"
41 #include "Page.h"
42 #include "RenderMedia.h"
43 #include "RenderSlider.h"
44 #include "RenderTheme.h"
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
toParentMediaElement(RenderObject * o)50 HTMLMediaElement* toParentMediaElement(RenderObject* o)
51 {
52 Node* node = o->node();
53 Node* mediaNode = node ? node->shadowAncestorNode() : 0;
54 if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag)))
55 return 0;
56
57 return static_cast<HTMLMediaElement*>(mediaNode);
58 }
59
60 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
61 static const float cSeekRepeatDelay = 0.1f;
62 static const float cStepTime = 0.07f;
63 static const float cSeekTime = 0.2f;
64
MediaControlShadowRootElement(Document * document,HTMLMediaElement * mediaElement)65 MediaControlShadowRootElement::MediaControlShadowRootElement(Document* document, HTMLMediaElement* mediaElement)
66 : HTMLDivElement(divTag, document)
67 , m_mediaElement(mediaElement)
68 {
69 RefPtr<RenderStyle> rootStyle = RenderStyle::create();
70 rootStyle->inheritFrom(mediaElement->renderer()->style());
71 rootStyle->setDisplay(BLOCK);
72 rootStyle->setPosition(RelativePosition);
73 RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(this);
74 renderer->setStyle(rootStyle.release());
75 setRenderer(renderer);
76 setAttached();
77 setInDocument(true);
78 }
79
updateStyle()80 void MediaControlShadowRootElement::updateStyle()
81 {
82 if (renderer()) {
83 RenderStyle* timelineContainerStyle = m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
84 renderer()->setStyle(timelineContainerStyle);
85 }
86 }
87
88 // ----------------------------
89
MediaControlElement(Document * document,PseudoId pseudo,HTMLMediaElement * mediaElement)90 MediaControlElement::MediaControlElement(Document* document, PseudoId pseudo, HTMLMediaElement* mediaElement)
91 : HTMLDivElement(divTag, document)
92 , m_mediaElement(mediaElement)
93 , m_pseudoStyleId(pseudo)
94 {
95 setInDocument(true);
96 switch (pseudo) {
97 case MEDIA_CONTROLS_CURRENT_TIME_DISPLAY:
98 m_displayType = MediaCurrentTimeDisplay;
99 break;
100 case MEDIA_CONTROLS_TIME_REMAINING_DISPLAY:
101 m_displayType = MediaTimeRemainingDisplay;
102 break;
103 case MEDIA_CONTROLS_TIMELINE_CONTAINER:
104 m_displayType = MediaTimelineContainer;
105 break;
106 case MEDIA_CONTROLS_STATUS_DISPLAY:
107 m_displayType = MediaStatusDisplay;
108 break;
109 case MEDIA_CONTROLS_PANEL:
110 m_displayType = MediaControlsPanel;
111 break;
112 case MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER:
113 m_displayType = MediaVolumeSliderContainer;
114 break;
115 default:
116 ASSERT_NOT_REACHED();
117 break;
118 }
119 }
120
attachToParent(Element * parent)121 void MediaControlElement::attachToParent(Element* parent)
122 {
123 parent->addChild(this);
124 }
125
update()126 void MediaControlElement::update()
127 {
128 if (renderer())
129 renderer()->updateFromElement();
130 updateStyle();
131 }
132
styleForElement()133 PassRefPtr<RenderStyle> MediaControlElement::styleForElement()
134 {
135 RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
136 if (!style)
137 return 0;
138
139 // text-decoration can't be overrided from CSS. So we do it here.
140 // See https://bugs.webkit.org/show_bug.cgi?id=27015
141 style->setTextDecoration(TDNONE);
142 style->setTextDecorationsInEffect(TDNONE);
143
144 return style;
145 }
146
rendererIsNeeded(RenderStyle * style)147 bool MediaControlElement::rendererIsNeeded(RenderStyle* style)
148 {
149 ASSERT(document()->page());
150
151 return HTMLDivElement::rendererIsNeeded(style) && parent() && parent()->renderer()
152 && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
153 }
154
attach()155 void MediaControlElement::attach()
156 {
157 RefPtr<RenderStyle> style = styleForElement();
158 if (!style)
159 return;
160 bool needsRenderer = rendererIsNeeded(style.get());
161 if (!needsRenderer)
162 return;
163 RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
164 if (!renderer)
165 return;
166 renderer->setStyle(style.get());
167 setRenderer(renderer);
168 if (parent() && parent()->renderer()) {
169 // Find next sibling with a renderer to determine where to insert.
170 Node* sibling = nextSibling();
171 while (sibling && !sibling->renderer())
172 sibling = sibling->nextSibling();
173 parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
174 }
175 ContainerNode::attach();
176 }
177
updateStyle()178 void MediaControlElement::updateStyle()
179 {
180 if (!m_mediaElement || !m_mediaElement->renderer())
181 return;
182
183 RefPtr<RenderStyle> style = styleForElement();
184 if (!style)
185 return;
186
187 bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer();
188 if (renderer() && !needsRenderer)
189 detach();
190 else if (!renderer() && needsRenderer)
191 attach();
192 else if (renderer()) {
193 renderer()->setStyle(style.get());
194
195 // Make sure that if there is any innerText renderer, it is updated as well.
196 if (firstChild() && firstChild()->renderer())
197 firstChild()->renderer()->setStyle(style.get());
198 }
199 }
200
201 // ----------------------------
202
MediaControlTimelineContainerElement(Document * document,HTMLMediaElement * element)203 MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(Document* document, HTMLMediaElement* element)
204 : MediaControlElement(document, MEDIA_CONTROLS_TIMELINE_CONTAINER, element)
205 {
206 }
207
rendererIsNeeded(RenderStyle * style)208 bool MediaControlTimelineContainerElement::rendererIsNeeded(RenderStyle* style)
209 {
210 if (!MediaControlElement::rendererIsNeeded(style))
211 return false;
212
213 // This is for MediaControllerThemeClassic:
214 // If there is no style for MediaControlStatusDisplayElement style, don't hide
215 // the timeline.
216 if (!m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_STATUS_DISPLAY))
217 return true;
218
219 float duration = m_mediaElement->duration();
220 return !isnan(duration) && !isinf(duration);
221 }
222
223 // ----------------------------
224
MediaControlVolumeSliderContainerElement(Document * doc,HTMLMediaElement * element)225 MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(Document* doc, HTMLMediaElement* element)
226 : MediaControlElement(doc, MEDIA_CONTROLS_VOLUME_SLIDER_CONTAINER, element)
227 , m_isVisible(false)
228 , m_x(0)
229 , m_y(0)
230 {
231 }
232
styleForElement()233 PassRefPtr<RenderStyle> MediaControlVolumeSliderContainerElement::styleForElement()
234 {
235 RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
236 style->setPosition(AbsolutePosition);
237 style->setLeft(Length(m_x, Fixed));
238 style->setTop(Length(m_y, Fixed));
239 style->setDisplay(m_isVisible ? BLOCK : NONE);
240 return style;
241 }
242
setVisible(bool visible)243 void MediaControlVolumeSliderContainerElement::setVisible(bool visible)
244 {
245 if (visible == m_isVisible)
246 return;
247 m_isVisible = visible;
248 }
249
setPosition(int x,int y)250 void MediaControlVolumeSliderContainerElement::setPosition(int x, int y)
251 {
252 if (x == m_x && y == m_y)
253 return;
254 m_x = x;
255 m_y = y;
256 }
257
hitTest(const IntPoint & absPoint)258 bool MediaControlVolumeSliderContainerElement::hitTest(const IntPoint& absPoint)
259 {
260 if (renderer() && renderer()->style()->hasAppearance())
261 return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
262
263 return false;
264 }
265
266 // ----------------------------
267
MediaControlStatusDisplayElement(Document * document,HTMLMediaElement * element)268 MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(Document* document, HTMLMediaElement* element)
269 : MediaControlElement(document, MEDIA_CONTROLS_STATUS_DISPLAY, element)
270 , m_stateBeingDisplayed(Nothing)
271 {
272 }
273
update()274 void MediaControlStatusDisplayElement::update()
275 {
276 MediaControlElement::update();
277
278 // Get the new state that we'll have to display.
279 StateBeingDisplayed newStateToDisplay = Nothing;
280
281 if (m_mediaElement->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !m_mediaElement->currentSrc().isEmpty())
282 newStateToDisplay = Loading;
283 else if (m_mediaElement->movieLoadType() == MediaPlayer::LiveStream)
284 newStateToDisplay = LiveBroadcast;
285
286 // Propagate only if needed.
287 if (newStateToDisplay == m_stateBeingDisplayed)
288 return;
289 m_stateBeingDisplayed = newStateToDisplay;
290
291 ExceptionCode e;
292 switch (m_stateBeingDisplayed) {
293 case Nothing:
294 setInnerText("", e);
295 break;
296 case Loading:
297 setInnerText(mediaElementLoadingStateText(), e);
298 break;
299 case LiveBroadcast:
300 setInnerText(mediaElementLiveBroadcastStateText(), e);
301 break;
302 }
303 }
304
rendererIsNeeded(RenderStyle * style)305 bool MediaControlStatusDisplayElement::rendererIsNeeded(RenderStyle* style)
306 {
307 if (!MediaControlElement::rendererIsNeeded(style))
308 return false;
309 float duration = m_mediaElement->duration();
310 return (isnan(duration) || isinf(duration));
311 }
312
313 // ----------------------------
314
MediaControlInputElement(Document * document,PseudoId pseudo,const String & type,HTMLMediaElement * mediaElement)315 MediaControlInputElement::MediaControlInputElement(Document* document, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement)
316 : HTMLInputElement(inputTag, document)
317 , m_mediaElement(mediaElement)
318 , m_pseudoStyleId(pseudo)
319 {
320 setInputType(type);
321 setInDocument(true);
322
323 switch (pseudo) {
324 case MEDIA_CONTROLS_MUTE_BUTTON:
325 m_displayType = MediaMuteButton;
326 break;
327 case MEDIA_CONTROLS_PLAY_BUTTON:
328 m_displayType = MediaPlayButton;
329 break;
330 case MEDIA_CONTROLS_SEEK_FORWARD_BUTTON:
331 m_displayType = MediaSeekForwardButton;
332 break;
333 case MEDIA_CONTROLS_SEEK_BACK_BUTTON:
334 m_displayType = MediaSeekBackButton;
335 break;
336 case MEDIA_CONTROLS_FULLSCREEN_BUTTON:
337 m_displayType = MediaFullscreenButton;
338 break;
339 case MEDIA_CONTROLS_TIMELINE:
340 m_displayType = MediaSlider;
341 break;
342 case MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON:
343 m_displayType = MediaReturnToRealtimeButton;
344 break;
345 case MEDIA_CONTROLS_REWIND_BUTTON:
346 m_displayType = MediaRewindButton;
347 break;
348 case MEDIA_CONTROLS_VOLUME_SLIDER:
349 m_displayType = MediaVolumeSlider;
350 break;
351 case MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON:
352 m_displayType = MediaShowClosedCaptionsButton;
353 break;
354 default:
355 ASSERT_NOT_REACHED();
356 break;
357 }
358 }
359
attachToParent(Element * parent)360 void MediaControlInputElement::attachToParent(Element* parent)
361 {
362 parent->addChild(this);
363 }
364
update()365 void MediaControlInputElement::update()
366 {
367 updateDisplayType();
368 if (renderer())
369 renderer()->updateFromElement();
370 updateStyle();
371 }
372
styleForElement()373 PassRefPtr<RenderStyle> MediaControlInputElement::styleForElement()
374 {
375 return m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
376 }
377
rendererIsNeeded(RenderStyle * style)378 bool MediaControlInputElement::rendererIsNeeded(RenderStyle* style)
379 {
380 ASSERT(document()->page());
381
382 return HTMLInputElement::rendererIsNeeded(style) && parent() && parent()->renderer()
383 && (!style->hasAppearance() || document()->page()->theme()->shouldRenderMediaControlPart(style->appearance(), m_mediaElement));
384 }
385
attach()386 void MediaControlInputElement::attach()
387 {
388 RefPtr<RenderStyle> style = styleForElement();
389 if (!style)
390 return;
391
392 bool needsRenderer = rendererIsNeeded(style.get());
393 if (!needsRenderer)
394 return;
395 RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style.get());
396 if (!renderer)
397 return;
398 renderer->setStyle(style.get());
399 setRenderer(renderer);
400 if (parent() && parent()->renderer()) {
401 // Find next sibling with a renderer to determine where to insert.
402 Node* sibling = nextSibling();
403 while (sibling && !sibling->renderer())
404 sibling = sibling->nextSibling();
405 parent()->renderer()->addChild(renderer, sibling ? sibling->renderer() : 0);
406 }
407 ContainerNode::attach();
408 }
409
updateStyle()410 void MediaControlInputElement::updateStyle()
411 {
412 if (!m_mediaElement || !m_mediaElement->renderer())
413 return;
414
415 RefPtr<RenderStyle> style = styleForElement();
416 if (!style)
417 return;
418
419 bool needsRenderer = rendererIsNeeded(style.get()) && parent() && parent()->renderer();
420 if (renderer() && !needsRenderer)
421 detach();
422 else if (!renderer() && needsRenderer)
423 attach();
424 else if (renderer())
425 renderer()->setStyle(style.get());
426 }
427
hitTest(const IntPoint & absPoint)428 bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
429 {
430 if (renderer() && renderer()->style()->hasAppearance())
431 return renderer()->theme()->hitTestMediaControlPart(renderer(), absPoint);
432
433 return false;
434 }
435
setDisplayType(MediaControlElementType displayType)436 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType)
437 {
438 if (displayType == m_displayType)
439 return;
440
441 m_displayType = displayType;
442 if (RenderObject* object = renderer())
443 object->repaint();
444 }
445
446 // ----------------------------
447
MediaControlMuteButtonElement(Document * document,HTMLMediaElement * element)448 MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, HTMLMediaElement* element)
449 : MediaControlInputElement(document, MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
450 {
451 }
452
defaultEventHandler(Event * event)453 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
454 {
455 if (event->type() == eventNames().clickEvent) {
456 m_mediaElement->setMuted(!m_mediaElement->muted());
457 event->setDefaultHandled();
458 }
459 HTMLInputElement::defaultEventHandler(event);
460 }
461
updateDisplayType()462 void MediaControlMuteButtonElement::updateDisplayType()
463 {
464 setDisplayType(m_mediaElement->muted() ? MediaUnMuteButton : MediaMuteButton);
465 }
466
467 // ----------------------------
468
MediaControlPlayButtonElement(Document * document,HTMLMediaElement * element)469 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* document, HTMLMediaElement* element)
470 : MediaControlInputElement(document, MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
471 {
472 }
473
defaultEventHandler(Event * event)474 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
475 {
476 if (event->type() == eventNames().clickEvent) {
477 m_mediaElement->togglePlayState();
478 event->setDefaultHandled();
479 }
480 HTMLInputElement::defaultEventHandler(event);
481 }
482
updateDisplayType()483 void MediaControlPlayButtonElement::updateDisplayType()
484 {
485 setDisplayType(m_mediaElement->canPlay() ? MediaPlayButton : MediaPauseButton);
486 }
487
488 // ----------------------------
489
MediaControlSeekButtonElement(Document * document,HTMLMediaElement * element,bool forward)490 MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, HTMLMediaElement* element, bool forward)
491 : MediaControlInputElement(document, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON,
492 "button", element)
493 , m_forward(forward)
494 , m_seeking(false)
495 , m_capturing(false)
496 , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
497 {
498 }
499
defaultEventHandler(Event * event)500 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
501 {
502 if (event->type() == eventNames().mousedownEvent) {
503 if (Frame* frame = document()->frame()) {
504 m_capturing = true;
505 frame->eventHandler()->setCapturingMouseEventsNode(this);
506 }
507 m_mediaElement->pause(event->fromUserGesture());
508 m_seekTimer.startRepeating(cSeekRepeatDelay);
509 event->setDefaultHandled();
510 } else if (event->type() == eventNames().mouseupEvent) {
511 if (m_capturing)
512 if (Frame* frame = document()->frame()) {
513 m_capturing = false;
514 frame->eventHandler()->setCapturingMouseEventsNode(0);
515 }
516 ExceptionCode ec;
517 if (m_seeking || m_seekTimer.isActive()) {
518 if (!m_seeking) {
519 float stepTime = m_forward ? cStepTime : -cStepTime;
520 m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + stepTime, ec);
521 }
522 m_seekTimer.stop();
523 m_seeking = false;
524 event->setDefaultHandled();
525 }
526 }
527 HTMLInputElement::defaultEventHandler(event);
528 }
529
seekTimerFired(Timer<MediaControlSeekButtonElement> *)530 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
531 {
532 ExceptionCode ec;
533 m_seeking = true;
534 float seekTime = m_forward ? cSeekTime : -cSeekTime;
535 m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + seekTime, ec);
536 }
537
detach()538 void MediaControlSeekButtonElement::detach()
539 {
540 if (m_capturing) {
541 if (Frame* frame = document()->frame())
542 frame->eventHandler()->setCapturingMouseEventsNode(0);
543 }
544 MediaControlInputElement::detach();
545 }
546
547
548 // ----------------------------
549
MediaControlRewindButtonElement(Document * document,HTMLMediaElement * element)550 MediaControlRewindButtonElement::MediaControlRewindButtonElement(Document* document, HTMLMediaElement* element)
551 : MediaControlInputElement(document, MEDIA_CONTROLS_REWIND_BUTTON, "button", element)
552 {
553 }
554
defaultEventHandler(Event * event)555 void MediaControlRewindButtonElement::defaultEventHandler(Event* event)
556 {
557 if (event->type() == eventNames().clickEvent) {
558 m_mediaElement->rewind(30);
559 event->setDefaultHandled();
560 }
561 HTMLInputElement::defaultEventHandler(event);
562 }
563
564
565 // ----------------------------
566
MediaControlReturnToRealtimeButtonElement(Document * document,HTMLMediaElement * element)567 MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(Document* document, HTMLMediaElement* element)
568 : MediaControlInputElement(document, MEDIA_CONTROLS_RETURN_TO_REALTIME_BUTTON, "button", element)
569 {
570 }
571
defaultEventHandler(Event * event)572 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event)
573 {
574 if (event->type() == eventNames().clickEvent) {
575 m_mediaElement->returnToRealtime();
576 event->setDefaultHandled();
577 }
578 HTMLInputElement::defaultEventHandler(event);
579 }
580
581
582 // ----------------------------
583
MediaControlToggleClosedCaptionsButtonElement(Document * doc,HTMLMediaElement * element)584 MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(Document* doc, HTMLMediaElement* element)
585 : MediaControlInputElement(doc, MEDIA_CONTROLS_TOGGLE_CLOSED_CAPTIONS_BUTTON, "button", element)
586 {
587 }
588
defaultEventHandler(Event * event)589 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event)
590 {
591 if (event->type() == eventNames().clickEvent) {
592 m_mediaElement->setClosedCaptionsVisible(!m_mediaElement->closedCaptionsVisible());
593 setChecked(m_mediaElement->closedCaptionsVisible());
594 event->setDefaultHandled();
595 }
596 HTMLInputElement::defaultEventHandler(event);
597 }
598
updateDisplayType()599 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType()
600 {
601 setDisplayType(m_mediaElement->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton);
602 }
603
604
605 // ----------------------------
606
MediaControlTimelineElement(Document * document,HTMLMediaElement * element)607 MediaControlTimelineElement::MediaControlTimelineElement(Document* document, HTMLMediaElement* element)
608 : MediaControlInputElement(document, MEDIA_CONTROLS_TIMELINE, "range", element)
609 {
610 }
611
defaultEventHandler(Event * event)612 void MediaControlTimelineElement::defaultEventHandler(Event* event)
613 {
614 // Left button is 0. Rejects mouse events not from left button.
615 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
616 return;
617
618 if (event->type() == eventNames().mousedownEvent)
619 m_mediaElement->beginScrubbing();
620
621 MediaControlInputElement::defaultEventHandler(event);
622
623 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
624 return;
625
626 float time = narrowPrecisionToFloat(value().toDouble());
627 if (time != m_mediaElement->currentTime()) {
628 ExceptionCode ec;
629 m_mediaElement->setCurrentTime(time, ec);
630 }
631
632 RenderSlider* slider = toRenderSlider(renderer());
633 if (slider && slider->inDragMode())
634 toRenderMedia(m_mediaElement->renderer())->updateTimeDisplay();
635
636 if (event->type() == eventNames().mouseupEvent)
637 m_mediaElement->endScrubbing();
638 }
639
update(bool updateDuration)640 void MediaControlTimelineElement::update(bool updateDuration)
641 {
642 if (updateDuration) {
643 float dur = m_mediaElement->duration();
644 setAttribute(maxAttr, String::number(isfinite(dur) ? dur : 0));
645 }
646 setValue(String::number(m_mediaElement->currentTime()));
647 MediaControlInputElement::update();
648 }
649
650 // ----------------------------
651
MediaControlVolumeSliderElement(Document * document,HTMLMediaElement * element)652 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document, HTMLMediaElement* element)
653 : MediaControlInputElement(document, MEDIA_CONTROLS_VOLUME_SLIDER, "range", element)
654 {
655 }
656
defaultEventHandler(Event * event)657 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
658 {
659 // Left button is 0. Rejects mouse events not from left button.
660 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
661 return;
662
663 MediaControlInputElement::defaultEventHandler(event);
664
665 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
666 return;
667
668 float volume = narrowPrecisionToFloat(value().toDouble());
669 if (volume != m_mediaElement->volume()) {
670 ExceptionCode ec = 0;
671 m_mediaElement->setVolume(volume, ec);
672 ASSERT(!ec);
673 }
674 }
675
update()676 void MediaControlVolumeSliderElement::update()
677 {
678 float volume = m_mediaElement->volume();
679 if (value().toFloat() != volume)
680 setValue(String::number(volume));
681 MediaControlInputElement::update();
682 }
683
684 // ----------------------------
685
MediaControlFullscreenButtonElement(Document * document,HTMLMediaElement * element)686 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* document, HTMLMediaElement* element)
687 : MediaControlInputElement(document, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element)
688 {
689 }
690
defaultEventHandler(Event * event)691 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
692 {
693 if (event->type() == eventNames().clickEvent) {
694 m_mediaElement->enterFullscreen();
695 event->setDefaultHandled();
696 }
697 HTMLInputElement::defaultEventHandler(event);
698 }
699
700 // ----------------------------
701
MediaControlTimeDisplayElement(Document * document,PseudoId pseudo,HTMLMediaElement * element)702 MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, PseudoId pseudo, HTMLMediaElement* element)
703 : MediaControlElement(document, pseudo, element)
704 , m_currentValue(0)
705 , m_isVisible(true)
706 {
707 }
708
styleForElement()709 PassRefPtr<RenderStyle> MediaControlTimeDisplayElement::styleForElement()
710 {
711 RefPtr<RenderStyle> style = MediaControlElement::styleForElement();
712 if (!m_isVisible) {
713 style = RenderStyle::clone(style.get());
714 style->setWidth(Length(0, Fixed));
715 }
716 return style;
717 }
718
setVisible(bool visible)719 void MediaControlTimeDisplayElement::setVisible(bool visible)
720 {
721 if (visible == m_isVisible)
722 return;
723 m_isVisible = visible;
724
725 // This function is used during the RenderMedia::layout()
726 // call, where we cannot change the renderer at this time.
727 if (!renderer() || !renderer()->style())
728 return;
729
730 RefPtr<RenderStyle> style = styleForElement();
731 renderer()->setStyle(style.get());
732 }
733
setCurrentValue(float time)734 void MediaControlTimeDisplayElement::setCurrentValue(float time)
735 {
736 m_currentValue = time;
737 }
738
739
740 } //namespace WebCore
741 #endif // enable(video)
742