2 * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
29 #include "RenderMedia.h"
31 #include "EventNames.h"
32 #include "FloatConversion.h"
33 #include "HTMLNames.h"
34 #include "MediaControlElements.h"
35 #include "MouseEvent.h"
37 #include "RenderLayer.h"
38 #include "RenderTheme.h"
39 #include <wtf/CurrentTime.h>
40 #include <wtf/MathExtras.h>
46 using namespace HTMLNames;
48 static const double cTimeUpdateRepeatDelay = 0.2;
49 static const double cOpacityAnimationRepeatDelay = 0.05;
51 RenderMedia::RenderMedia(HTMLMediaElement* video)
53 , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
54 , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
56 , m_opacityAnimationStartTime(0)
57 , m_opacityAnimationDuration(0)
58 , m_opacityAnimationFrom(0)
59 , m_opacityAnimationTo(1.0f)
61 setImageResource(RenderImageResource::create());
64 RenderMedia::RenderMedia(HTMLMediaElement* video, const IntSize& intrinsicSize)
66 , m_timeUpdateTimer(this, &RenderMedia::timeUpdateTimerFired)
67 , m_opacityAnimationTimer(this, &RenderMedia::opacityAnimationTimerFired)
69 , m_opacityAnimationStartTime(0)
70 , m_opacityAnimationDuration(0)
71 , m_opacityAnimationFrom(0)
72 , m_opacityAnimationTo(1.0f)
74 setImageResource(RenderImageResource::create());
75 setIntrinsicSize(intrinsicSize);
78 RenderMedia::~RenderMedia()
82 void RenderMedia::destroy()
84 if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) {
86 // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach()
87 // when display: style changes
90 removeChild(m_controlsShadowRoot->renderer());
91 m_controlsShadowRoot->detach();
92 m_controlsShadowRoot = 0;
94 RenderImage::destroy();
97 HTMLMediaElement* RenderMedia::mediaElement() const
99 return static_cast<HTMLMediaElement*>(node());
102 MediaPlayer* RenderMedia::player() const
104 return mediaElement()->player();
107 void RenderMedia::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
109 RenderImage::styleDidChange(diff, oldStyle);
111 if (m_controlsShadowRoot) {
113 m_panel->updateStyle();
115 m_muteButton->updateStyle();
117 m_playButton->updateStyle();
118 if (m_seekBackButton)
119 m_seekBackButton->updateStyle();
120 if (m_seekForwardButton)
121 m_seekForwardButton->updateStyle();
123 m_rewindButton->updateStyle();
124 if (m_returnToRealtimeButton)
125 m_returnToRealtimeButton->updateStyle();
126 if (m_toggleClosedCaptionsButton)
127 m_toggleClosedCaptionsButton->updateStyle();
129 m_statusDisplay->updateStyle();
130 if (m_timelineContainer)
131 m_timelineContainer->updateStyle();
133 m_timeline->updateStyle();
134 if (m_fullscreenButton)
135 m_fullscreenButton->updateStyle();
136 if (m_currentTimeDisplay)
137 m_currentTimeDisplay->updateStyle();
138 if (m_timeRemainingDisplay)
139 m_timeRemainingDisplay->updateStyle();
140 if (m_volumeSliderContainer)
141 m_volumeSliderContainer->updateStyle();
142 if (m_volumeSliderMuteButton)
143 m_volumeSliderMuteButton->updateStyle();
145 m_volumeSlider->updateStyle();
149 void RenderMedia::layout()
151 IntSize oldSize = contentBoxRect().size();
153 RenderImage::layout();
155 RenderBox* controlsRenderer = m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
156 if (!controlsRenderer)
158 IntSize newSize = contentBoxRect().size();
159 if (newSize != oldSize || controlsRenderer->needsLayout()) {
161 if (m_currentTimeDisplay && m_timeRemainingDisplay) {
162 bool shouldShowTimeDisplays = shouldShowTimeDisplayControls();
163 m_currentTimeDisplay->setVisible(shouldShowTimeDisplays);
164 m_timeRemainingDisplay->setVisible(shouldShowTimeDisplays);
167 controlsRenderer->setLocation(borderLeft() + paddingLeft(), borderTop() + paddingTop());
168 controlsRenderer->style()->setHeight(Length(newSize.height(), Fixed));
169 controlsRenderer->style()->setWidth(Length(newSize.width(), Fixed));
170 controlsRenderer->setNeedsLayout(true, false);
171 controlsRenderer->layout();
172 setChildNeedsLayout(false);
176 void RenderMedia::createControlsShadowRoot()
178 ASSERT(!m_controlsShadowRoot);
179 m_controlsShadowRoot = MediaControlShadowRootElement::create(mediaElement());
180 addChild(m_controlsShadowRoot->renderer());
183 void RenderMedia::createPanel()
186 m_panel = MediaControlElement::create(mediaElement(), MEDIA_CONTROLS_PANEL);
187 m_panel->attachToParent(m_controlsShadowRoot.get());
190 void RenderMedia::createMuteButton()
192 ASSERT(!m_muteButton);
193 m_muteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::Controller);
194 m_muteButton->attachToParent(m_panel.get());
197 void RenderMedia::createPlayButton()
199 ASSERT(!m_playButton);
200 m_playButton = MediaControlPlayButtonElement::create(mediaElement());
201 m_playButton->attachToParent(m_panel.get());
204 void RenderMedia::createSeekBackButton()
206 ASSERT(!m_seekBackButton);
207 m_seekBackButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_BACK_BUTTON);
208 m_seekBackButton->attachToParent(m_panel.get());
211 void RenderMedia::createSeekForwardButton()
213 ASSERT(!m_seekForwardButton);
214 m_seekForwardButton = MediaControlSeekButtonElement::create(mediaElement(), MEDIA_CONTROLS_SEEK_FORWARD_BUTTON);
215 m_seekForwardButton->attachToParent(m_panel.get());
218 void RenderMedia::createRewindButton()
220 ASSERT(!m_rewindButton);
221 m_rewindButton = MediaControlRewindButtonElement::create(mediaElement());
222 m_rewindButton->attachToParent(m_panel.get());
225 void RenderMedia::createReturnToRealtimeButton()
227 ASSERT(!m_returnToRealtimeButton);
228 m_returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(mediaElement());
229 m_returnToRealtimeButton->attachToParent(m_panel.get());
232 void RenderMedia::createToggleClosedCaptionsButton()
234 ASSERT(!m_toggleClosedCaptionsButton);
235 m_toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(mediaElement());
236 m_toggleClosedCaptionsButton->attachToParent(m_panel.get());
239 void RenderMedia::createStatusDisplay()
241 ASSERT(!m_statusDisplay);
242 m_statusDisplay = MediaControlStatusDisplayElement::create(mediaElement());
243 m_statusDisplay->attachToParent(m_panel.get());
246 void RenderMedia::createTimelineContainer()
248 ASSERT(!m_timelineContainer);
249 m_timelineContainer = MediaControlTimelineContainerElement::create(mediaElement());
250 m_timelineContainer->attachToParent(m_panel.get());
253 void RenderMedia::createTimeline()
256 m_timeline = MediaControlTimelineElement::create(mediaElement());
257 m_timeline->setAttribute(precisionAttr, "float");
258 m_timeline->attachToParent(m_timelineContainer.get());
261 void RenderMedia::createVolumeSliderContainer()
263 ASSERT(!m_volumeSliderContainer);
264 m_volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(mediaElement());
265 m_volumeSliderContainer->attachToParent(m_panel.get());
268 void RenderMedia::createVolumeSlider()
270 ASSERT(!m_volumeSlider);
271 m_volumeSlider = MediaControlVolumeSliderElement::create(mediaElement());
272 m_volumeSlider->setAttribute(precisionAttr, "float");
273 m_volumeSlider->setAttribute(maxAttr, "1");
274 m_volumeSlider->setAttribute(valueAttr, String::number(mediaElement()->volume()));
275 m_volumeSlider->attachToParent(m_volumeSliderContainer.get());
278 void RenderMedia::createVolumeSliderMuteButton()
280 ASSERT(!m_volumeSliderMuteButton);
281 m_volumeSliderMuteButton = MediaControlMuteButtonElement::create(mediaElement(), MediaControlMuteButtonElement::VolumeSlider);
282 m_volumeSliderMuteButton->attachToParent(m_volumeSliderContainer.get());
286 void RenderMedia::createCurrentTimeDisplay()
288 ASSERT(!m_currentTimeDisplay);
289 m_currentTimeDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_CURRENT_TIME_DISPLAY);
290 m_currentTimeDisplay->attachToParent(m_timelineContainer.get());
293 void RenderMedia::createTimeRemainingDisplay()
295 ASSERT(!m_timeRemainingDisplay);
296 m_timeRemainingDisplay = MediaControlTimeDisplayElement::create(mediaElement(), MEDIA_CONTROLS_TIME_REMAINING_DISPLAY);
297 m_timeRemainingDisplay->attachToParent(m_timelineContainer.get());
300 void RenderMedia::createFullscreenButton()
302 ASSERT(!m_fullscreenButton);
303 m_fullscreenButton = MediaControlFullscreenButtonElement::create(mediaElement());
304 m_fullscreenButton->attachToParent(m_panel.get());
307 void RenderMedia::updateFromElement()
312 void RenderMedia::updateControls()
314 HTMLMediaElement* media = mediaElement();
315 if (!media->controls() || !media->inActiveDocument()) {
316 if (m_controlsShadowRoot) {
317 m_controlsShadowRoot->detach();
322 m_timelineContainer = 0;
324 m_seekBackButton = 0;
325 m_seekForwardButton = 0;
327 m_returnToRealtimeButton = 0;
328 m_currentTimeDisplay = 0;
329 m_timeRemainingDisplay = 0;
330 m_fullscreenButton = 0;
331 m_volumeSliderContainer = 0;
333 m_volumeSliderMuteButton = 0;
334 m_controlsShadowRoot = 0;
335 m_toggleClosedCaptionsButton = 0;
337 m_opacityAnimationTo = 1.0f;
338 m_opacityAnimationTimer.stop();
339 m_timeUpdateTimer.stop();
343 if (!m_controlsShadowRoot) {
344 createControlsShadowRoot();
347 createRewindButton();
349 createReturnToRealtimeButton();
350 createStatusDisplay();
351 createTimelineContainer();
352 if (m_timelineContainer) {
353 createCurrentTimeDisplay();
355 createTimeRemainingDisplay();
357 createSeekBackButton();
358 createSeekForwardButton();
359 createToggleClosedCaptionsButton();
360 createFullscreenButton();
362 createVolumeSliderContainer();
363 if (m_volumeSliderContainer) {
364 createVolumeSlider();
365 createVolumeSliderMuteButton();
371 if (media->canPlay()) {
372 if (m_timeUpdateTimer.isActive())
373 m_timeUpdateTimer.stop();
374 } else if (style()->visibility() == VISIBLE && m_timeline && m_timeline->renderer() && m_timeline->renderer()->style()->display() != NONE) {
375 m_timeUpdateTimer.startRepeating(cTimeUpdateRepeatDelay);
380 // update() might alter the opacity of the element, especially if we are in the middle
381 // of an animation. This is the only element concerned as we animate only this element.
382 float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0;
384 changeOpacity(m_panel.get(), opacityBeforeChangingStyle);
387 m_muteButton->update();
389 m_playButton->update();
390 if (m_timelineContainer)
391 m_timelineContainer->update();
392 if (m_volumeSliderContainer)
393 m_volumeSliderContainer->update();
395 m_timeline->update();
396 if (m_currentTimeDisplay)
397 m_currentTimeDisplay->update();
398 if (m_timeRemainingDisplay)
399 m_timeRemainingDisplay->update();
400 if (m_seekBackButton)
401 m_seekBackButton->update();
402 if (m_seekForwardButton)
403 m_seekForwardButton->update();
405 m_rewindButton->update();
406 if (m_returnToRealtimeButton)
407 m_returnToRealtimeButton->update();
408 if (m_toggleClosedCaptionsButton)
409 m_toggleClosedCaptionsButton->update();
411 m_statusDisplay->update();
412 if (m_fullscreenButton)
413 m_fullscreenButton->update();
415 m_volumeSlider->update();
416 if (m_volumeSliderMuteButton)
417 m_volumeSliderMuteButton->update();
420 updateControlVisibility();
423 void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*)
426 m_timeline->update(false);
430 void RenderMedia::updateTimeDisplay()
432 if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || style()->visibility() != VISIBLE)
435 float now = mediaElement()->currentTime();
436 float duration = mediaElement()->duration();
438 // Allow the theme to format the time
440 m_currentTimeDisplay->setInnerText(theme()->formatMediaControlsCurrentTime(now, duration), ec);
441 m_currentTimeDisplay->setCurrentValue(now);
442 m_timeRemainingDisplay->setInnerText(theme()->formatMediaControlsRemainingTime(now, duration), ec);
443 m_timeRemainingDisplay->setCurrentValue(now - duration);
446 void RenderMedia::updateControlVisibility()
448 if (!m_panel || !m_panel->renderer())
451 // Don't fade for audio controls.
452 HTMLMediaElement* media = mediaElement();
453 if (!media->hasVideo())
456 // Don't fade if the media element is not visible
457 if (style()->visibility() != VISIBLE)
460 bool shouldHideController = !m_mouseOver && !media->canPlay();
462 // Do fading manually, css animations don't work with shadow trees
464 float animateFrom = m_panel->renderer()->style()->opacity();
465 float animateTo = shouldHideController ? 0.0f : 1.0f;
467 if (animateFrom == animateTo)
470 if (m_opacityAnimationTimer.isActive()) {
471 if (m_opacityAnimationTo == animateTo)
473 m_opacityAnimationTimer.stop();
476 if (animateFrom < animateTo)
477 m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
479 m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
481 m_opacityAnimationFrom = animateFrom;
482 m_opacityAnimationTo = animateTo;
484 m_opacityAnimationStartTime = currentTime();
485 m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay);
488 void RenderMedia::changeOpacity(HTMLElement* e, float opacity)
490 if (!e || !e->renderer() || !e->renderer()->style())
492 RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style());
493 s->setOpacity(opacity);
494 // z-index can't be auto if opacity is used
496 e->renderer()->setStyle(s.release());
499 void RenderMedia::opacityAnimationTimerFired(Timer<RenderMedia>*)
501 double time = currentTime() - m_opacityAnimationStartTime;
502 if (time >= m_opacityAnimationDuration) {
503 time = m_opacityAnimationDuration;
504 m_opacityAnimationTimer.stop();
506 float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration);
507 changeOpacity(m_panel.get(), opacity);
510 void RenderMedia::updateVolumeSliderContainer(bool visible)
512 if (!mediaElement()->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider)
515 if (visible && !m_volumeSliderContainer->isVisible()) {
516 if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox())
519 RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
520 int height = s->height().isPercent() ? 0 : s->height().value();
521 int width = s->width().isPercent() ? 0 : s->width().value();
522 IntPoint offset = document()->page()->theme()->volumeSliderOffsetFromMuteButton(m_muteButton->renderer()->node(), IntSize(width, height));
523 int x = offset.x() + m_muteButton->renderBox()->offsetLeft();
524 int y = offset.y() + m_muteButton->renderBox()->offsetTop();
526 m_volumeSliderContainer->setPosition(x, y);
527 m_volumeSliderContainer->setVisible(true);
528 m_volumeSliderContainer->update();
529 m_volumeSlider->update();
530 } else if (!visible && m_volumeSliderContainer->isVisible()) {
531 m_volumeSliderContainer->setVisible(false);
532 m_volumeSliderContainer->updateStyle();
536 void RenderMedia::forwardEvent(Event* event)
538 if (event->isMouseEvent() && m_controlsShadowRoot) {
539 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
540 IntPoint point(mouseEvent->absoluteLocation());
542 bool defaultHandled = false;
543 if (m_volumeSliderMuteButton && m_volumeSliderMuteButton->hitTest(point)) {
544 m_volumeSliderMuteButton->defaultEventHandler(event);
545 defaultHandled = event->defaultHandled();
548 bool showVolumeSlider = false;
549 if (!defaultHandled && m_muteButton && m_muteButton->hitTest(point)) {
550 m_muteButton->defaultEventHandler(event);
551 if (event->type() != eventNames().mouseoutEvent)
552 showVolumeSlider = true;
555 if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point))
556 showVolumeSlider = true;
558 if (m_volumeSlider && m_volumeSlider->hitTest(point)) {
559 m_volumeSlider->defaultEventHandler(event);
560 showVolumeSlider = true;
563 updateVolumeSliderContainer(showVolumeSlider);
565 if (m_playButton && m_playButton->hitTest(point))
566 m_playButton->defaultEventHandler(event);
568 if (m_seekBackButton && m_seekBackButton->hitTest(point))
569 m_seekBackButton->defaultEventHandler(event);
571 if (m_seekForwardButton && m_seekForwardButton->hitTest(point))
572 m_seekForwardButton->defaultEventHandler(event);
574 if (m_rewindButton && m_rewindButton->hitTest(point))
575 m_rewindButton->defaultEventHandler(event);
577 if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point))
578 m_returnToRealtimeButton->defaultEventHandler(event);
580 if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point))
581 m_toggleClosedCaptionsButton->defaultEventHandler(event);
583 if (m_timeline && m_timeline->hitTest(point))
584 m_timeline->defaultEventHandler(event);
586 if (m_fullscreenButton && m_fullscreenButton->hitTest(point))
587 m_fullscreenButton->defaultEventHandler(event);
589 if (event->type() == eventNames().mouseoverEvent) {
591 updateControlVisibility();
593 if (event->type() == eventNames().mouseoutEvent) {
594 // 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
595 Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0;
596 RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0;
597 m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(this);
598 updateControlVisibility();
603 int RenderMedia::topmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
605 int top = RenderImage::topmostPosition(includeOverflowInterior, includeSelf, applyTransform);
606 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
609 top = min(top, m_controlsShadowRoot->renderBox()->transformedFrameRect().y() + m_controlsShadowRoot->renderBox()->topmostPosition(includeOverflowInterior, includeSelf, applyTransform));
611 if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
612 int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
613 int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
614 int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
615 IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
616 return transformRect.y();
622 int RenderMedia::lowestPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
624 int bottom = RenderImage::lowestPosition(includeOverflowInterior, includeSelf, applyTransform);
625 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
628 bottom = max(bottom, m_controlsShadowRoot->renderBox()->transformedFrameRect().y() + m_controlsShadowRoot->renderBox()->lowestPosition(includeOverflowInterior, includeSelf, applyTransform));
630 if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
631 int top = topmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
632 int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
633 int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
634 IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
635 return transformRect.height() + transformRect.y();
641 int RenderMedia::rightmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
643 int right = RenderImage::rightmostPosition(includeOverflowInterior, includeSelf, applyTransform);
644 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
647 right = max(right, m_controlsShadowRoot->renderBox()->transformedFrameRect().x() + m_controlsShadowRoot->renderBox()->rightmostPosition(includeOverflowInterior, includeSelf, applyTransform));
649 if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
650 int top = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
651 int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
652 int left = leftmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
653 IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
654 return transformRect.width() + transformRect.x();
660 int RenderMedia::leftmostPosition(bool includeOverflowInterior, bool includeSelf, ApplyTransform applyTransform) const
662 int left = RenderImage::leftmostPosition(includeOverflowInterior, includeSelf, applyTransform);
663 if (!m_controlsShadowRoot || !m_controlsShadowRoot->renderer())
666 left = min(left, m_controlsShadowRoot->renderBox()->transformedFrameRect().x() + m_controlsShadowRoot->renderBox()->leftmostPosition(includeOverflowInterior, includeSelf, applyTransform));
668 if (applyTransform == IncludeTransform && includeSelf && layer() && layer()->hasTransform()) {
669 int top = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
670 int bottom = lowestPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
671 int right = rightmostPosition(includeOverflowInterior, includeSelf, ExcludeTransform);
672 IntRect transformRect = applyLayerTransformToRect(IntRect(left, top, right - left, bottom - top));
673 return transformRect.x();
680 // We want the timeline slider to be at least 100 pixels wide.
681 static const int minWidthToDisplayTimeDisplays = 16 + 16 + 45 + 100 + 45 + 16 + 1;
683 bool RenderMedia::shouldShowTimeDisplayControls() const
685 if (!m_currentTimeDisplay && !m_timeRemainingDisplay)
688 int width = mediaElement()->renderBox()->width();
689 return width >= minWidthToDisplayTimeDisplays * style()->effectiveZoom();
692 } // namespace WebCore