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