• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007, 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 
28 #if ENABLE(VIDEO)
29 #include "RenderMedia.h"
30 
31 #include "EventNames.h"
32 #include "FloatConversion.h"
33 #include "HTMLNames.h"
34 #include "MediaControlElements.h"
35 #include "MouseEvent.h"
36 #include "RenderTheme.h"
37 #include <wtf/CurrentTime.h>
38 #include <wtf/MathExtras.h>
39 
40 using namespace std;
41 
42 namespace WebCore {
43 
44 using namespace HTMLNames;
45 
46 static const double cTimeUpdateRepeatDelay = 0.2;
47 static const double cOpacityAnimationRepeatDelay = 0.05;
48 
RenderMedia(HTMLMediaElement * video)49 RenderMedia::RenderMedia(HTMLMediaElement* video)
50     : RenderImage(video)
51     , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
52     , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
53     , m_mouseOver(false)
54     , m_opacityAnimationStartTime(0)
55     , m_opacityAnimationDuration(0)
56     , m_opacityAnimationFrom(0)
57     , m_opacityAnimationTo(1.0f)
58 {
59 }
60 
RenderMedia(HTMLMediaElement * video,const IntSize & intrinsicSize)61 RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
62     : RenderImage(video)
63     , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
64     , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
65     , m_mouseOver(false)
66     , m_opacityAnimationStartTime(0)
67     , m_opacityAnimationDuration(0)
68     , m_opacityAnimationFrom(0)
69     , m_opacityAnimationTo(1.0f)
70 {
71     setIntrinsicSize(intrinsicSize);
72 }
73 
~RenderMedia()74 RenderMedia::~RenderMedia()
75 {
76 }
77 
destroy()78 void RenderMedia::destroy()
79 {
80     if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) {
81 
82         // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach()
83         //  when display: style changes
84         m_panel->detach();
85 
86         removeChild(m_controlsShadowRoot->renderer());
87         m_controlsShadowRoot->detach();
88         m_controlsShadowRoot = 0;
89     }
90     RenderImage::destroy();
91 }
92 
mediaElement() const93 HTMLMediaElement* RenderMedia::mediaElement() const
94 {
95     return static_cast<HTMLMediaElement*>(node());
96 }
97 
player() const98 MediaPlayer* RenderMedia::player() const
99 {
100     return mediaElement()->player();
101 }
102 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)103 void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
104 {
105     RenderImage::styleDidChange(diff, oldStyle);
106 
107     if (m_controlsShadowRoot) {
108         if (m_panel)
109             m_panel->updateStyle();
110         if (m_muteButton)
111             m_muteButton->updateStyle();
112         if (m_playButton)
113             m_playButton->updateStyle();
114         if (m_seekBackButton)
115             m_seekBackButton->updateStyle();
116         if (m_seekForwardButton)
117             m_seekForwardButton->updateStyle();
118         if (m_rewindButton)
119             m_rewindButton->updateStyle();
120         if (m_returnToRealtimeButton)
121             m_returnToRealtimeButton->updateStyle();
122         if (m_toggleClosedCaptionsButton)
123             m_toggleClosedCaptionsButton->updateStyle();
124         if (m_statusDisplay)
125             m_statusDisplay->updateStyle();
126         if (m_timelineContainer)
127             m_timelineContainer->updateStyle();
128         if (m_timeline)
129             m_timeline->updateStyle();
130         if (m_fullscreenButton)
131             m_fullscreenButton->updateStyle();
132         if (m_currentTimeDisplay)
133             m_currentTimeDisplay->updateStyle();
134         if (m_timeRemainingDisplay)
135             m_timeRemainingDisplay->updateStyle();
136         if (m_volumeSliderContainer)
137             m_volumeSliderContainer->updateStyle();
138         if (m_volumeSlider)
139             m_volumeSlider->updateStyle();
140     }
141 }
142 
layout()143 void RenderMedia::layout()
144 {
145     IntSize oldSize = contentBoxRect().size();
146 
147     RenderImage::layout();
148 
149     RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
150     if (!controlsRenderer)
151         return;
152     IntSize newSize = contentBoxRect().size();
153     if (newSize != oldSize || controlsRenderer->needsLayout()) {
154 
155         if (m_currentTimeDisplay && m_timeRemainingDisplay) {
156             bool shouldShowTimeDisplays = shouldShowTimeDisplayControls();
157             m_currentTimeDisplay->setVisible(shouldShowTimeDisplays);
158             m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays);
159         }
160 
161         controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop());
162         controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
163         controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
164         controlsRenderer->setNeedsLayout(true, false);
165         controlsRenderer->layout();
166         setChildNeedsLayout(false);
167     }
168 }
169 
createControlsShadowRoot()170 void RenderMedia::createControlsShadowRoot()
171 {
172     ASSERT(!m_controlsShadowRoot);
173     m_controlsShadowRoot = new MediaControlShadowRootElement(document(), mediaElement());
174     addChild(m_controlsShadowRoot->renderer());
175 }
176 
createPanel()177 void RenderMedia::createPanel()
178 {
179     ASSERT(!m_panel);
180     m_panel = new MediaControlElement(document(), MEDIA_CONTROLS_PANEL, mediaElement());
181     m_panel->attachToParent(m_controlsShadowRoot.get());
182 }
183 
createMuteButton()184 void RenderMedia::createMuteButton()
185 {
186     ASSERT(!m_muteButton);
187     m_muteButton = new MediaControlMuteButtonElement(document(), mediaElement());
188     m_muteButton->attachToParent(m_panel.get());
189 }
190 
createPlayButton()191 void RenderMedia::createPlayButton()
192 {
193     ASSERT(!m_playButton);
194     m_playButton = new MediaControlPlayButtonElement(document(), mediaElement());
195     m_playButton->attachToParent(m_panel.get());
196 }
197 
createSeekBackButton()198 void RenderMedia::createSeekBackButton()
199 {
200     ASSERT(!m_seekBackButton);
201     m_seekBackButton = new MediaControlSeekButtonElement(document(), mediaElement(), false);
202     m_seekBackButton->attachToParent(m_panel.get());
203 }
204 
createSeekForwardButton()205 void RenderMedia::createSeekForwardButton()
206 {
207     ASSERT(!m_seekForwardButton);
208     m_seekForwardButton = new MediaControlSeekButtonElement(document(), mediaElement(), true);
209     m_seekForwardButton->attachToParent(m_panel.get());
210 }
211 
createRewindButton()212 void RenderMedia::createRewindButton()
213 {
214     ASSERT(!m_rewindButton);
215     m_rewindButton = new MediaControlRewindButtonElement(document(), mediaElement());
216     m_rewindButton->attachToParent(m_panel.get());
217 }
218 
createReturnToRealtimeButton()219 void RenderMedia::createReturnToRealtimeButton()
220 {
221     ASSERT(!m_returnToRealtimeButton);
222     m_returnToRealtimeButton = new MediaControlReturnToRealtimeButtonElement(document(), mediaElement());
223     m_returnToRealtimeButton->attachToParent(m_panel.get());
224 }
225 
createToggleClosedCaptionsButton()226 void RenderMedia::createToggleClosedCaptionsButton()
227 {
228     ASSERT(!m_toggleClosedCaptionsButton);
229     m_toggleClosedCaptionsButton = new MediaControlToggleClosedCaptionsButtonElement(document(), mediaElement());
230     m_toggleClosedCaptionsButton->attachToParent(m_panel.get());
231 }
232 
createStatusDisplay()233 void RenderMedia::createStatusDisplay()
234 {
235     ASSERT(!m_statusDisplay);
236     m_statusDisplay = new MediaControlStatusDisplayElement(document(), mediaElement());
237     m_statusDisplay->attachToParent(m_panel.get());
238 }
239 
createTimelineContainer()240 void RenderMedia::createTimelineContainer()
241 {
242     ASSERT(!m_timelineContainer);
243     m_timelineContainer = new MediaControlTimelineContainerElement(document(), mediaElement());
244     m_timelineContainer->attachToParent(m_panel.get());
245 }
246 
createTimeline()247 void RenderMedia::createTimeline()
248 {
249     ASSERT(!m_timeline);
250     m_timeline = new MediaControlTimelineElement(document(), mediaElement());
251     m_timeline->setAttribute(precisionAttr, "float");
252     m_timeline->attachToParent(m_timelineContainer.get());
253 }
254 
createVolumeSliderContainer()255 void RenderMedia::createVolumeSliderContainer()
256 {
257     ASSERT(!m_volumeSliderContainer);
258     m_volumeSliderContainer = new MediaControlVolumeSliderContainerElement(document(), mediaElement());
259     m_volumeSliderContainer->attachToParent(m_panel.get());
260 }
261 
createVolumeSlider()262 void RenderMedia::createVolumeSlider()
263 {
264     ASSERT(!m_volumeSlider);
265     m_volumeSlider = new MediaControlVolumeSliderElement(document(), mediaElement());
266     m_volumeSlider->setAttribute(precisionAttr, "float");
267     m_volumeSlider->setAttribute(maxAttr, "1");
268     m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume()));
269     m_volumeSlider->attachToParent(m_volumeSliderContainer.get());
270 }
271 
createCurrentTimeDisplay()272 void RenderMedia::createCurrentTimeDisplay()
273 {
274     ASSERT(!m_currentTimeDisplay);
275     m_currentTimeDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY, mediaElement());
276     m_currentTimeDisplay->attachToParent(m_timelineContainer.get());
277 }
278 
createTimeRemainingDisplay()279 void RenderMedia::createTimeRemainingDisplay()
280 {
281     ASSERT(!m_timeRemainingDisplay);
282     m_timeRemainingDisplay = new MediaControlTimeDisplayElement(document(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, mediaElement());
283     m_timeRemainingDisplay->attachToParent(m_timelineContainer.get());
284 }
285 
createFullscreenButton()286 void RenderMedia::createFullscreenButton()
287 {
288     ASSERT(!m_fullscreenButton);
289     m_fullscreenButton = new MediaControlFullscreenButtonElement(document(), mediaElement());
290     m_fullscreenButton->attachToParent(m_panel.get());
291 }
292 
updateFromElement()293 void RenderMedia::updateFromElement()
294 {
295     updateControls();
296 }
297 
updateControls()298 void RenderMedia::updateControls()
299 {
300     HTMLMediaElement* media = mediaElement();
301     if (!media->controls() || !media->inActiveDocument()) {
302         if (m_controlsShadowRoot) {
303             m_controlsShadowRoot->detach();
304             m_panel = 0;
305             m_muteButton = 0;
306             m_playButton = 0;
307             m_statusDisplay = 0;
308             m_timelineContainer = 0;
309             m_timeline = 0;
310             m_seekBackButton = 0;
311             m_seekForwardButton = 0;
312             m_rewindButton = 0;
313             m_returnToRealtimeButton = 0;
314             m_currentTimeDisplay = 0;
315             m_timeRemainingDisplay = 0;
316             m_fullscreenButton = 0;
317             m_volumeSliderContainer = 0;
318             m_volumeSlider = 0;
319             m_controlsShadowRoot = 0;
320             m_toggleClosedCaptionsButton = 0;
321         }
322         m_opacityAnimationTo = 1.0f;
323         m_opacityAnimationTimer.stop();
324         m_timeUpdateTimer.stop();
325         return;
326     }
327 
328     if (!m_controlsShadowRoot) {
329         createControlsShadowRoot();
330         createPanel();
331         if (m_panel) {
332             createRewindButton();
333             createPlayButton();
334             createReturnToRealtimeButton();
335             createStatusDisplay();
336             createTimelineContainer();
337             if (m_timelineContainer) {
338                 createCurrentTimeDisplay();
339                 createTimeline();
340                 createTimeRemainingDisplay();
341             }
342             createSeekBackButton();
343             createSeekForwardButton();
344             createToggleClosedCaptionsButton();
345             createFullscreenButton();
346             createMuteButton();
347             createVolumeSliderContainer();
348             if (m_volumeSliderContainer)
349                 createVolumeSlider();
350             m_panel->attach();
351         }
352     }
353 
354     if (media->canPlay()) {
355         if (m_timeUpdateTimer.isActive())
356             m_timeUpdateTimer.stop();
357     } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE) {
358         m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay);
359     }
360 
361 
362     if (m_panel) {
363         // update() might alter the opacity of the element, especially if we are in the middle
364         // of an animation. This is the only element concerned as we animate only this element.
365         float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0;
366         m_panel->update();
367         changeOpacity(m_panel.get(), opacityBeforeChangingStyle);
368     }
369     if (m_muteButton)
370         m_muteButton->update();
371     if (m_playButton)
372         m_playButton->update();
373     if (m_timelineContainer)
374         m_timelineContainer->update();
375     if (m_volumeSliderContainer)
376         m_volumeSliderContainer->update();
377     if (m_timeline)
378         m_timeline->update();
379     if (m_currentTimeDisplay)
380         m_currentTimeDisplay->update();
381     if (m_timeRemainingDisplay)
382         m_timeRemainingDisplay->update();
383     if (m_seekBackButton)
384         m_seekBackButton->update();
385     if (m_seekForwardButton)
386         m_seekForwardButton->update();
387     if (m_rewindButton)
388         m_rewindButton->update();
389     if (m_returnToRealtimeButton)
390         m_returnToRealtimeButton->update();
391     if (m_toggleClosedCaptionsButton)
392         m_toggleClosedCaptionsButton->update();
393     if (m_statusDisplay)
394         m_statusDisplay->update();
395     if (m_fullscreenButton)
396         m_fullscreenButton->update();
397     if (m_volumeSlider)
398         m_volumeSlider->update();
399 
400     updateTimeDisplay();
401     updateControlVisibility();
402 }
403 
timeUpdateTimerFired(Timer<RenderMedia> *)404 void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*)
405 {
406     if (m_timeline)
407         m_timeline->update(false);
408     updateTimeDisplay();
409 }
410 
updateTimeDisplay()411 void RenderMedia::updateTimeDisplay()
412 {
413     if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE)
414         return;
415 
416     float now = mediaElement()->currentTime();
417     float duration = mediaElement()->duration();
418 
419     // Allow the theme to format the time
420     ExceptionCode ec;
421     m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec);
422     m_currentTimeDisplay->setCurrentValue(now);
423     m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec);
424     m_timeRemainingDisplay->setCurrentValue(now - duration);
425 }
426 
updateControlVisibility()427 void RenderMedia::updateControlVisibility()
428 {
429     if (!m_panel || !m_panel->renderer())
430         return;
431 
432     // Don't fade for audio controls.
433     HTMLMediaElement* media = mediaElement();
434     if (!media->hasVideo())
435         return;
436 
437     // Don't fade if the media element is not visible
438     if (style()->visibility() != VISIBLE)
439         return;
440 
441     bool shouldHideController = !m_mouseOver && !media->canPlay();
442 
443     // Do fading manually, css animations don't work with shadow trees
444 
445     float animateFrom = m_panel->renderer()->style()->opacity();
446     float animateTo = shouldHideController ? 0.0f : 1.0f;
447 
448     if (animateFrom == animateTo)
449         return;
450 
451     if (m_opacityAnimationTimer.isActive()) {
452         if (m_opacityAnimationTo == animateTo)
453             return;
454         m_opacityAnimationTimer.stop();
455     }
456 
457     if (animateFrom < animateTo)
458         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
459     else
460         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
461 
462     m_opacityAnimationFrom = animateFrom;
463     m_opacityAnimationTo = animateTo;
464 
465     m_opacityAnimationStartTime = currentTime();
466     m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay);
467 }
468 
changeOpacity(HTMLElement * e,float opacity)469 void RenderMedia::changeOpacity(HTMLElement* e, float opacity)
470 {
471     if (!e || !e->renderer() || !e->renderer()->style())
472         return;
473     RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style());
474     s->setOpacity(opacity);
475     // z-index can't be auto if opacity is used
476     s->setZIndex(0);
477     e->renderer()->setStyle(s.release());
478 }
479 
opacityAnimationTimerFired(Timer<RenderMedia> *)480 void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*)
481 {
482     double time = currentTime() - m_opacityAnimationStartTime;
483     if (time >= m_opacityAnimationDuration) {
484         time = m_opacityAnimationDuration;
485         m_opacityAnimationTimer.stop();
486     }
487     float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration);
488     changeOpacity(m_panel.get(), opacity);
489 }
490 
updateVolumeSliderContainer(bool visible)491 void RenderMedia::updateVolumeSliderContainer(bool visible)
492 {
493     if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider)
494         return;
495 
496     if (visible && !m_volumeSliderContainer->isVisible()) {
497         if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox())
498             return;
499 
500         RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
501         int height = s->height().isPercent() ? 0 : s->height().value();
502         int x = m_muteButton->renderBox()->offsetLeft();
503         int y = m_muteButton->renderBox()->offsetTop() - height;
504         FloatPoint absPoint = m_muteButton->renderer()->localToAbsolute(FloatPoint(x, y), true, true);
505         if (absPoint.y() < 0)
506             y = m_muteButton->renderBox()->offsetTop() + m_muteButton->renderBox()->height();
507         m_volumeSliderContainer->setVisible(true);
508         m_volumeSliderContainer->setPosition(x, y);
509         m_volumeSliderContainer->update();
510         m_volumeSlider->update();
511     } else if (!visible && m_volumeSliderContainer->isVisible()) {
512         m_volumeSliderContainer->setVisible(false);
513         m_volumeSliderContainer->updateStyle();
514     }
515 }
516 
forwardEvent(Event * event)517 void RenderMedia::forwardEvent(Event* event)
518 {
519     if (event->isMouseEvent() && m_controlsShadowRoot) {
520         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
521         IntPoint point(mouseEvent->absoluteLocation());
522         bool showVolumeSlider = false;
523         if (m_muteButton && m_muteButton->hitTest(point)) {
524             m_muteButton->defaultEventHandler(event);
525             if (event->type() != eventNames().mouseoutEvent)
526                 showVolumeSlider = true;
527         }
528 
529         if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point))
530             showVolumeSlider = true;
531 
532         if (m_volumeSlider && m_volumeSlider->hitTest(point)) {
533             m_volumeSlider->defaultEventHandler(event);
534             showVolumeSlider = true;
535         }
536 
537         updateVolumeSliderContainer(showVolumeSlider);
538 
539         if (m_playButton && m_playButton->hitTest(point))
540             m_playButton->defaultEventHandler(event);
541 
542         if (m_seekBackButton && m_seekBackButton->hitTest(point))
543             m_seekBackButton->defaultEventHandler(event);
544 
545         if (m_seekForwardButton && m_seekForwardButton->hitTest(point))
546             m_seekForwardButton->defaultEventHandler(event);
547 
548         if (m_rewindButton && m_rewindButton->hitTest(point))
549             m_rewindButton->defaultEventHandler(event);
550 
551         if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point))
552             m_returnToRealtimeButton->defaultEventHandler(event);
553 
554        if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point))
555             m_toggleClosedCaptionsButton->defaultEventHandler(event);
556 
557         if (m_timeline && m_timeline->hitTest(point))
558             m_timeline->defaultEventHandler(event);
559 
560         if (m_fullscreenButton && m_fullscreenButton->hitTest(point))
561             m_fullscreenButton->defaultEventHandler(event);
562 
563         if (event->type() == eventNames().mouseoverEvent) {
564             m_mouseOver = true;
565             updateControlVisibility();
566         }
567         if (event->type() == eventNames().mouseoutEvent) {
568             // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant
569             Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0;
570             RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0;
571             m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this);
572             updateControlVisibility();
573         }
574     }
575 }
576 
lowestPosition(bool includeOverflowInterior,bool includeSelf) const577 int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
578 {
579     int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf);
580     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
581         return bottom;
582 
583     return max(bottom,  m_controlsShadowRoot->renderBox()->y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf));
584 }
585 
rightmostPosition(bool includeOverflowInterior,bool includeSelf) const586 int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
587 {
588     int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf);
589     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
590         return right;
591 
592     return max(right, m_controlsShadowRoot->renderBox()->x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf));
593 }
594 
leftmostPosition(bool includeOverflowInterior,bool includeSelf) const595 int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
596 {
597     int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf);
598     if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
599         return left;
600 
601     return min(left, m_controlsShadowRoot->renderBox()->x() +  m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf));
602 }
603 
604 
605 // We want the timeline slider to be at least 100 pixels wide.
606 static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1;
607 
shouldShowTimeDisplayControls() const608 bool RenderMedia::shouldShowTimeDisplayControls() const
609 {
610     if (!m_currentTimeDisplay && !m_timeRemainingDisplay)
611         return false;
612 
613     int width = mediaElement()->renderBox()->width();
614     return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom();
615 }
616 
617 } // namespace WebCore
618 
619 #endif
620