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 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 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 74 RenderMedia::~RenderMedia() 75 { 76 } 77 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 93 HTMLMediaElement* RenderMedia::mediaElement() const 94 { 95 return static_cast<HTMLMediaElement*>(node()); 96 } 97 98 MediaPlayer* RenderMedia::player() const 99 { 100 return mediaElement()->player(); 101 } 102 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 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 170 void RenderMedia::createControlsShadowRoot() 171 { 172 ASSERT(!m_controlsShadowRoot); 173 m_controlsShadowRoot = new MediaControlShadowRootElement(document(), mediaElement()); 174 addChild(m_controlsShadowRoot->renderer()); 175 } 176 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 293 void RenderMedia::updateFromElement() 294 { 295 updateControls(); 296 } 297 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 404 void RenderMedia::timeUpdateTimerFired(Timer<RenderMedia>*) 405 { 406 if (m_timeline) 407 m_timeline->update(false); 408 updateTimeDisplay(); 409 } 410 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 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 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 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 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 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 577 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 586 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 595 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 608 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