1/* 2 * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2011 Google Inc. All rights reserved. 4 * Copyright (C) 2012 Research In Motion Limited. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "config.h" 29 30#if ENABLE(VIDEO) 31#include "MediaControlsBlackBerry.h" 32 33#include "Chrome.h" 34#include "DOMTokenList.h" 35#include "ExceptionCodePlaceholder.h" 36#include "Frame.h" 37#include "HTMLMediaElement.h" 38#include "HTMLNames.h" 39#include "MediaControlElements.h" 40#include "MouseEvent.h" 41#include "Page.h" 42#include "RenderDeprecatedFlexibleBox.h" 43#include "RenderSlider.h" 44#include "RenderTheme.h" 45#include "Settings.h" 46#include "Text.h" 47 48#if ENABLE(VIDEO_TRACK) 49#include "TextTrackCue.h" 50#endif 51 52using namespace std; 53 54namespace WebCore { 55 56using namespace HTMLNames; 57 58static const double timeWithoutMouseMovementBeforeHidingControls = 3; 59 60inline MediaControlButtonGroupContainerElement::MediaControlButtonGroupContainerElement(Document* document) 61 : MediaControlDivElement(document, MediaControlsPanel) 62{ 63} 64 65PassRefPtr<MediaControlButtonGroupContainerElement> MediaControlButtonGroupContainerElement::create(Document* document) 66{ 67 RefPtr<MediaControlButtonGroupContainerElement> element = adoptRef(new MediaControlButtonGroupContainerElement(document)); 68 return element.release(); 69} 70 71const AtomicString& MediaControlButtonGroupContainerElement::shadowPseudoId() const 72{ 73 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-button-group-container", AtomicString::ConstructFromLiteral)); 74 return id; 75} 76 77inline MediaControlTimeDisplayContainerElement::MediaControlTimeDisplayContainerElement(Document* document) 78 : MediaControlDivElement(document, MediaControlsPanel) 79{ 80} 81 82PassRefPtr<MediaControlTimeDisplayContainerElement> MediaControlTimeDisplayContainerElement::create(Document* document) 83{ 84 RefPtr<MediaControlTimeDisplayContainerElement> element = adoptRef(new MediaControlTimeDisplayContainerElement(document)); 85 return element.release(); 86} 87 88const AtomicString& MediaControlTimeDisplayContainerElement::shadowPseudoId() const 89{ 90 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-display-container", AtomicString::ConstructFromLiteral)); 91 return id; 92} 93 94MediaControlEmbeddedPanelElement::MediaControlEmbeddedPanelElement(Document* document) 95 : MediaControlDivElement(document, MediaControlsPanel) 96 , m_canBeDragged(false) 97 , m_isBeingDragged(false) 98 , m_isDisplayed(false) 99 , m_opaque(true) 100 , m_transitionTimer(this, &MediaControlEmbeddedPanelElement::transitionTimerFired) 101{ 102} 103 104PassRefPtr<MediaControlEmbeddedPanelElement> MediaControlEmbeddedPanelElement::create(Document* document) 105{ 106 return adoptRef(new MediaControlEmbeddedPanelElement(document)); 107} 108 109const AtomicString& MediaControlEmbeddedPanelElement::shadowPseudoId() const 110{ 111 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-embedded-panel", AtomicString::ConstructFromLiteral)); 112 return id; 113} 114 115void MediaControlEmbeddedPanelElement::startDrag(const LayoutPoint& eventLocation) 116{ 117 if (!m_canBeDragged) 118 return; 119 120 if (m_isBeingDragged) 121 return; 122 123 RenderObject* renderer = this->renderer(); 124 if (!renderer || !renderer->isBox()) 125 return; 126 127 Frame* frame = document()->frame(); 128 if (!frame) 129 return; 130 131 m_lastDragEventLocation = eventLocation; 132 133 frame->eventHandler()->setCapturingMouseEventsNode(this); 134 135 m_isBeingDragged = true; 136} 137 138void MediaControlEmbeddedPanelElement::continueDrag(const LayoutPoint& eventLocation) 139{ 140 if (!m_isBeingDragged) 141 return; 142 143 LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation; 144 m_cumulativeDragOffset.move(distanceDragged); 145 m_lastDragEventLocation = eventLocation; 146 setPosition(m_cumulativeDragOffset); 147} 148 149void MediaControlEmbeddedPanelElement::endDrag() 150{ 151 if (!m_isBeingDragged) 152 return; 153 154 m_isBeingDragged = false; 155 156 Frame* frame = document()->frame(); 157 if (!frame) 158 return; 159 160 frame->eventHandler()->setCapturingMouseEventsNode(0); 161} 162 163void MediaControlEmbeddedPanelElement::startTimer() 164{ 165 stopTimer(); 166 167 // The timer is required to set the property display:'none' on the panel, 168 // such that captions are correctly displayed at the bottom of the video 169 // at the end of the fadeout transition. 170 double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; 171 m_transitionTimer.startOneShot(duration); 172} 173 174void MediaControlEmbeddedPanelElement::stopTimer() 175{ 176 if (m_transitionTimer.isActive()) 177 m_transitionTimer.stop(); 178} 179 180void MediaControlEmbeddedPanelElement::transitionTimerFired(Timer<MediaControlEmbeddedPanelElement>*) 181{ 182 if (!m_opaque) 183 hide(); 184 185 stopTimer(); 186} 187 188void MediaControlEmbeddedPanelElement::setPosition(const LayoutPoint& position) 189{ 190 double left = position.x(); 191 double top = position.y(); 192 193 // Set the left and top to control the panel's position; this depends on it being absolute positioned. 194 // Set the margin to zero since the position passed in will already include the effect of the margin. 195 setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX); 196 setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX); 197 setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX); 198 setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX); 199 200 classList()->add("dragged", IGNORE_EXCEPTION); 201} 202 203void MediaControlEmbeddedPanelElement::resetPosition() 204{ 205 removeInlineStyleProperty(CSSPropertyLeft); 206 removeInlineStyleProperty(CSSPropertyTop); 207 removeInlineStyleProperty(CSSPropertyMarginLeft); 208 removeInlineStyleProperty(CSSPropertyMarginTop); 209 210 classList()->remove("dragged", IGNORE_EXCEPTION); 211 212 m_cumulativeDragOffset.setX(0); 213 m_cumulativeDragOffset.setY(0); 214} 215 216void MediaControlEmbeddedPanelElement::makeOpaque() 217{ 218 if (m_opaque) 219 return; 220 221 double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0; 222 223 setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity); 224 setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S); 225 setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER); 226 227 m_opaque = true; 228 229 if (m_isDisplayed) 230 show(); 231} 232 233void MediaControlEmbeddedPanelElement::makeTransparent() 234{ 235 if (!m_opaque) 236 return; 237 238 double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0; 239 240 setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity); 241 setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S); 242 setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER); 243 244 m_opaque = false; 245 startTimer(); 246} 247 248void MediaControlEmbeddedPanelElement::defaultEventHandler(Event* event) 249{ 250 MediaControlDivElement::defaultEventHandler(event); 251 252 if (event->isMouseEvent()) { 253 LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation(); 254 if (event->type() == eventNames().mousedownEvent && event->target() == this) { 255 startDrag(location); 256 event->setDefaultHandled(); 257 } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged) 258 continueDrag(location); 259 else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) { 260 continueDrag(location); 261 endDrag(); 262 event->setDefaultHandled(); 263 } 264 } 265} 266 267void MediaControlEmbeddedPanelElement::setCanBeDragged(bool canBeDragged) 268{ 269 if (m_canBeDragged == canBeDragged) 270 return; 271 272 m_canBeDragged = canBeDragged; 273 274 if (!canBeDragged) 275 endDrag(); 276} 277 278void MediaControlEmbeddedPanelElement::setIsDisplayed(bool isDisplayed) 279{ 280 m_isDisplayed = isDisplayed; 281} 282 283inline MediaControlFullscreenTimeDisplayContainerElement::MediaControlFullscreenTimeDisplayContainerElement(Document* document) 284 : MediaControlDivElement(document, MediaControlsPanel) 285{ 286} 287 288PassRefPtr<MediaControlFullscreenTimeDisplayContainerElement> MediaControlFullscreenTimeDisplayContainerElement::create(Document* document) 289{ 290 RefPtr<MediaControlFullscreenTimeDisplayContainerElement> element = adoptRef(new MediaControlFullscreenTimeDisplayContainerElement(document)); 291 return element.release(); 292} 293 294const AtomicString& MediaControlFullscreenTimeDisplayContainerElement::shadowPseudoId() const 295{ 296 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-display-container", AtomicString::ConstructFromLiteral)); 297 return id; 298} 299 300inline MediaControlFullscreenButtonContainerElement::MediaControlFullscreenButtonContainerElement(Document* document) 301 : MediaControlDivElement(document, MediaControlsPanel) 302{ 303} 304 305PassRefPtr<MediaControlFullscreenButtonContainerElement> MediaControlFullscreenButtonContainerElement::create(Document* document) 306{ 307 RefPtr<MediaControlFullscreenButtonContainerElement> element = adoptRef(new MediaControlFullscreenButtonContainerElement(document)); 308 return element.release(); 309} 310 311const AtomicString& MediaControlFullscreenButtonContainerElement::shadowPseudoId() const 312{ 313 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-container", AtomicString::ConstructFromLiteral)); 314 return id; 315} 316 317inline MediaControlFullscreenButtonDividerElement::MediaControlFullscreenButtonDividerElement(Document* document) 318 : MediaControlDivElement(document, MediaRewindButton) 319{ 320} 321 322PassRefPtr<MediaControlFullscreenButtonDividerElement> MediaControlFullscreenButtonDividerElement::create(Document* document) 323{ 324 RefPtr<MediaControlFullscreenButtonDividerElement> element = adoptRef(new MediaControlFullscreenButtonDividerElement(document)); 325 return element.release(); 326} 327 328const AtomicString& MediaControlFullscreenButtonDividerElement::shadowPseudoId() const 329{ 330 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-divider", AtomicString::ConstructFromLiteral)); 331 return id; 332} 333 334inline MediaControlPlayButtonContainerElement::MediaControlPlayButtonContainerElement(Document* document) 335 : MediaControlDivElement(document, MediaControlsPanel) 336{ 337} 338 339PassRefPtr<MediaControlPlayButtonContainerElement> MediaControlPlayButtonContainerElement::create(Document* document) 340{ 341 RefPtr<MediaControlPlayButtonContainerElement> element = adoptRef(new MediaControlPlayButtonContainerElement(document)); 342 return element.release(); 343} 344 345const AtomicString& MediaControlPlayButtonContainerElement::shadowPseudoId() const 346{ 347 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button-container", AtomicString::ConstructFromLiteral)); 348 return id; 349} 350 351inline MediaControlPlaceholderElement::MediaControlPlaceholderElement(Document* document) 352 : MediaControlDivElement(document, MediaControlsPanel) 353{ 354} 355 356PassRefPtr<MediaControlPlaceholderElement> MediaControlPlaceholderElement::create(Document* document) 357{ 358 RefPtr<MediaControlPlaceholderElement> element = adoptRef(new MediaControlPlaceholderElement(document)); 359 return element.release(); 360} 361 362const AtomicString& MediaControlPlaceholderElement::shadowPseudoId() const 363{ 364 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-placeholder", AtomicString::ConstructFromLiteral)); 365 return id; 366} 367 368inline MediaControlFullscreenPlayButtonElement::MediaControlFullscreenPlayButtonElement(Document* document) 369 : MediaControlInputElement(document, MediaPlayButton) 370{ 371} 372 373PassRefPtr<MediaControlFullscreenPlayButtonElement> MediaControlFullscreenPlayButtonElement::create(Document* document) 374{ 375 RefPtr<MediaControlFullscreenPlayButtonElement> button = adoptRef(new MediaControlFullscreenPlayButtonElement(document)); 376 button->ensureUserAgentShadowRoot(); 377 button->setType("button"); 378 return button.release(); 379} 380 381void MediaControlFullscreenPlayButtonElement::defaultEventHandler(Event* event) 382{ 383 if (event->type() == eventNames().clickEvent) { 384 if (mediaController()->canPlay()) 385 mediaController()->play(); 386 else 387 mediaController()->pause(); 388 updateDisplayType(); 389 event->setDefaultHandled(); 390 } 391 HTMLInputElement::defaultEventHandler(event); 392} 393 394void MediaControlFullscreenPlayButtonElement::updateDisplayType() 395{ 396 setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton); 397} 398 399const AtomicString& MediaControlFullscreenPlayButtonElement::shadowPseudoId() const 400{ 401 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-play-button", AtomicString::ConstructFromLiteral)); 402 return id; 403} 404 405inline MediaControlFullscreenFullscreenButtonElement::MediaControlFullscreenFullscreenButtonElement(Document* document) 406 : MediaControlInputElement(document, MediaExitFullscreenButton) 407{ 408} 409 410PassRefPtr<MediaControlFullscreenFullscreenButtonElement> MediaControlFullscreenFullscreenButtonElement::create(Document* document) 411{ 412 RefPtr<MediaControlFullscreenFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenFullscreenButtonElement(document)); 413 button->ensureUserAgentShadowRoot(); 414 button->setType("button"); 415 button->hide(); 416 return button.release(); 417} 418 419void MediaControlFullscreenFullscreenButtonElement::defaultEventHandler(Event* event) 420{ 421 if (event->type() == eventNames().clickEvent) { 422#if ENABLE(FULLSCREEN_API) 423 // Only use the new full screen API if the fullScreenEnabled setting has 424 // been explicitly enabled. Otherwise, use the old fullscreen API. This 425 // allows apps which embed a WebView to retain the existing full screen 426 // video implementation without requiring them to implement their own full 427 // screen behavior. 428 if (document()->settings() && document()->settings()->fullScreenEnabled()) { 429 if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this)) 430 document()->webkitCancelFullScreen(); 431 else 432 document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement); 433 } else 434#endif 435 mediaController()->enterFullscreen(); 436 event->setDefaultHandled(); 437 } 438 HTMLInputElement::defaultEventHandler(event); 439} 440 441const AtomicString& MediaControlFullscreenFullscreenButtonElement::shadowPseudoId() const 442{ 443 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-fullscreen-button", AtomicString::ConstructFromLiteral)); 444 return id; 445} 446 447void MediaControlFullscreenFullscreenButtonElement::setIsFullscreen(bool) 448{ 449 setDisplayType(MediaExitFullscreenButton); 450} 451 452inline MediaControlFullscreenTimelineContainerElement::MediaControlFullscreenTimelineContainerElement(Document* document) 453 : MediaControlDivElement(document, MediaTimelineContainer) 454{ 455} 456 457PassRefPtr<MediaControlFullscreenTimelineContainerElement> MediaControlFullscreenTimelineContainerElement::create(Document* document) 458{ 459 RefPtr<MediaControlFullscreenTimelineContainerElement> element = adoptRef(new MediaControlFullscreenTimelineContainerElement(document)); 460 element->hide(); 461 return element.release(); 462} 463 464const AtomicString& MediaControlFullscreenTimelineContainerElement::shadowPseudoId() const 465{ 466 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline-container", AtomicString::ConstructFromLiteral)); 467 return id; 468} 469 470MediaControlFullscreenTimelineElement::MediaControlFullscreenTimelineElement(Document* document, MediaControls* controls) 471 : MediaControlInputElement(document, MediaSlider) 472 , m_controls(controls) 473{ 474} 475 476PassRefPtr<MediaControlFullscreenTimelineElement> MediaControlFullscreenTimelineElement::create(Document* document, MediaControls* controls) 477{ 478 ASSERT(controls); 479 480 RefPtr<MediaControlFullscreenTimelineElement> timeline = adoptRef(new MediaControlFullscreenTimelineElement(document, controls)); 481 timeline->ensureUserAgentShadowRoot(); 482 timeline->setType("range"); 483 timeline->setAttribute(precisionAttr, "double"); 484 return timeline.release(); 485} 486 487void MediaControlFullscreenTimelineElement::defaultEventHandler(Event* event) 488{ 489 // Left button is 0. Rejects mouse events not from left button. 490 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) 491 return; 492 493 if (!attached()) 494 return; 495 496 if (event->type() == eventNames().mousedownEvent) 497 mediaController()->beginScrubbing(); 498 499 if (event->type() == eventNames().mouseupEvent) 500 mediaController()->endScrubbing(); 501 502 MediaControlInputElement::defaultEventHandler(event); 503 504 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) 505 return; 506 507 double time = value().toDouble(); 508 if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime()) 509 mediaController()->setCurrentTime(time, IGNORE_EXCEPTION); 510 511 RenderSlider* slider = toRenderSlider(renderer()); 512 if (slider && slider->inDragMode()) 513 m_controls->updateCurrentTimeDisplay(); 514} 515 516bool MediaControlFullscreenTimelineElement::willRespondToMouseClickEvents() 517{ 518 if (!attached()) 519 return false; 520 521 return true; 522} 523 524void MediaControlFullscreenTimelineElement::setPosition(double currentTime) 525{ 526 setValue(String::number(currentTime)); 527} 528 529void MediaControlFullscreenTimelineElement::setDuration(double duration) 530{ 531 setAttribute(maxAttr, String::number(std::isfinite(duration) ? duration : 0)); 532} 533 534const AtomicString& MediaControlFullscreenTimelineElement::shadowPseudoId() const 535{ 536 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline", AtomicString::ConstructFromLiteral)); 537 return id; 538} 539 540PassRefPtr<MediaControlFullscreenTimeRemainingDisplayElement> MediaControlFullscreenTimeRemainingDisplayElement::create(Document* document) 541{ 542 return adoptRef(new MediaControlFullscreenTimeRemainingDisplayElement(document)); 543} 544 545MediaControlFullscreenTimeRemainingDisplayElement::MediaControlFullscreenTimeRemainingDisplayElement(Document* document) 546 : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay) 547{ 548} 549 550const AtomicString& MediaControlFullscreenTimeRemainingDisplayElement::shadowPseudoId() const 551{ 552 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-remaining-display", AtomicString::ConstructFromLiteral)); 553 return id; 554} 555 556PassRefPtr<MediaControlFullscreenCurrentTimeDisplayElement> MediaControlFullscreenCurrentTimeDisplayElement::create(Document* document) 557{ 558 return adoptRef(new MediaControlFullscreenCurrentTimeDisplayElement(document)); 559} 560 561MediaControlFullscreenCurrentTimeDisplayElement::MediaControlFullscreenCurrentTimeDisplayElement(Document* document) 562 : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay) 563{ 564} 565 566const AtomicString& MediaControlFullscreenCurrentTimeDisplayElement::shadowPseudoId() const 567{ 568 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-current-time-display", AtomicString::ConstructFromLiteral)); 569 return id; 570} 571 572MediaControlAudioMuteButtonElement::MediaControlAudioMuteButtonElement(Document* document, MediaControls* controls) 573 : MediaControlMuteButtonElement(document, MediaMuteButton) 574 , m_controls(controls) 575{ 576} 577 578PassRefPtr<MediaControlAudioMuteButtonElement> MediaControlAudioMuteButtonElement::create(Document* document, MediaControls* controls) 579{ 580 ASSERT(controls); 581 582 RefPtr<MediaControlAudioMuteButtonElement> button = adoptRef(new MediaControlAudioMuteButtonElement(document, controls)); 583 button->ensureUserAgentShadowRoot(); 584 button->setType("button"); 585 return button.release(); 586} 587 588void MediaControlAudioMuteButtonElement::defaultEventHandler(Event* event) 589{ 590 if (event->type() == eventNames().mousedownEvent) { 591 // We do not mute when the media player volume/mute control is touched. 592 // Instead we show/hide the volume slider. 593 static_cast<MediaControlsBlackBerry*>(m_controls)->toggleVolumeSlider(); 594 event->setDefaultHandled(); 595 return; 596 } 597 if (event->type() == eventNames().mouseoverEvent) 598 m_controls->showVolumeSlider(); 599 600 MediaControlMuteButtonElement::defaultEventHandler(event); 601} 602 603const AtomicString& MediaControlAudioMuteButtonElement::shadowPseudoId() const 604{ 605 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-audio-mute-button", AtomicString::ConstructFromLiteral)); 606 return id; 607} 608 609MediaControlsBlackBerry::MediaControlsBlackBerry(Document* document) 610 : MediaControls(document) 611 , m_buttonContainer(0) 612 , m_timeDisplayContainer(0) 613 , m_fullscreenTimeDisplayContainer(0) 614 , m_fullscreenPlayButton(0) 615 , m_fullscreenCurrentTimeDisplay(0) 616 , m_fullscreenTimeline(0) 617 , m_timeRemainingDisplay(0) 618 , m_fullscreenTimeRemainingDisplay(0) 619 , m_timelineContainer(0) 620 , m_fullscreenTimelineContainer(0) 621 , m_fullScreenDivider(0) 622 , m_fullscreenFullScreenButton(0) 623 , m_muteButton(0) 624 , m_volumeSliderContainer(0) 625 , m_embeddedPanel(0) 626 , m_fullScreenButtonContainer(0) 627 , m_playButtonContainer(0) 628 , m_placeholder(0) 629{ 630} 631 632PassRefPtr<MediaControls> MediaControls::create(Document* document) 633{ 634 return MediaControlsBlackBerry::createControls(document); 635} 636 637PassRefPtr<MediaControlsBlackBerry> MediaControlsBlackBerry::createControls(Document* document) 638{ 639 if (!document->page()) 640 return 0; 641 642 RefPtr<MediaControlsBlackBerry> controls = adoptRef(new MediaControlsBlackBerry(document)); 643 644 RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document); 645 RefPtr<MediaControlEmbeddedPanelElement> embedPanel = MediaControlEmbeddedPanelElement::create(document); 646 647 ExceptionCode ec; 648 649 RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(document); 650 controls->m_playButton = playButton.get(); 651 embedPanel->appendChild(playButton.release(), ec, AttachLazily); 652 if (ec) 653 return 0; 654 655 RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(document); 656 657 RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, controls.get()); 658 controls->m_timeline = timeline.get(); 659 timelineContainer->appendChild(timeline.release(), ec, AttachLazily); 660 if (ec) 661 return 0; 662 663 RefPtr<MediaControlTimeDisplayContainerElement> timeDisplayContainer = MediaControlTimeDisplayContainerElement::create(document); 664 665 RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document); 666 controls->m_currentTimeDisplay = currentTimeDisplay.get(); 667 timeDisplayContainer->appendChild(currentTimeDisplay.release(), ec, AttachLazily); 668 if (ec) 669 return 0; 670 671 RefPtr<MediaControlTimeRemainingDisplayElement> timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document); 672 controls->m_timeRemainingDisplay = timeRemainingDisplay.get(); 673 timeDisplayContainer->appendChild(timeRemainingDisplay.release(), ec, AttachLazily); 674 if (ec) 675 return 0; 676 677 controls->m_timeDisplayContainer = timeDisplayContainer.get(); 678 timelineContainer->appendChild(timeDisplayContainer.release(), ec, AttachLazily); 679 if (ec) 680 return 0; 681 682 controls->m_timelineContainer = timelineContainer.get(); 683 embedPanel->appendChild(timelineContainer.release(), ec, AttachLazily); 684 if (ec) 685 return 0; 686 687 RefPtr<MediaControlFullscreenButtonElement> fullScreenButton = MediaControlFullscreenButtonElement::create(document); 688 controls->m_fullScreenButton = fullScreenButton.get(); 689 embedPanel->appendChild(fullScreenButton.release(), ec, AttachLazily); 690 if (ec) 691 return 0; 692 693 if (document->page()->theme()->usesMediaControlVolumeSlider()) { 694 // The mute button and the slider element should be in the same div. 695 RefPtr<HTMLDivElement> volumeControlContainer = HTMLDivElement::create(document); 696 697 RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document); 698 699 RefPtr<MediaControlPanelVolumeSliderElement> slider = MediaControlPanelVolumeSliderElement::create(document); 700 controls->m_volumeSlider = slider.get(); 701 volumeSliderContainer->appendChild(slider.release(), ec, AttachLazily); 702 if (ec) 703 return 0; 704 705 controls->m_volumeSliderContainer = volumeSliderContainer.get(); 706 volumeControlContainer->appendChild(volumeSliderContainer.release(), ec, AttachLazily); 707 if (ec) 708 return 0; 709 RefPtr<MediaControlAudioMuteButtonElement> muteButton = MediaControlAudioMuteButtonElement::create(document, controls.get()); 710 controls->m_muteButton = muteButton.get(); 711 volumeControlContainer->appendChild(muteButton.release(), ec, AttachLazily); 712 if (ec) 713 return 0; 714 715 embedPanel->appendChild(volumeControlContainer.release(), ec, AttachLazily); 716 if (ec) 717 return 0; 718 } 719 720 RefPtr<MediaControlFullscreenTimelineContainerElement> fullscreenTimelineContainer = MediaControlFullscreenTimelineContainerElement::create(document); 721 722 RefPtr<MediaControlFullscreenTimelineElement> fullscreenTimeline = MediaControlFullscreenTimelineElement::create(document, controls.get()); 723 controls->m_fullscreenTimeline = fullscreenTimeline.get(); 724 fullscreenTimelineContainer->appendChild(fullscreenTimeline.release(), ec, AttachLazily); 725 if (ec) 726 return 0; 727 728 RefPtr<MediaControlFullscreenTimeDisplayContainerElement> fullscreenTimeDisplayContainer = MediaControlFullscreenTimeDisplayContainerElement::create(document); 729 730 RefPtr<MediaControlFullscreenCurrentTimeDisplayElement> fullscreenCurrentTimeDisplay = MediaControlFullscreenCurrentTimeDisplayElement::create(document); 731 controls->m_fullscreenCurrentTimeDisplay = fullscreenCurrentTimeDisplay.get(); 732 fullscreenTimeDisplayContainer->appendChild(fullscreenCurrentTimeDisplay.release(), ec, AttachLazily); 733 if (ec) 734 return 0; 735 736 RefPtr<MediaControlFullscreenTimeRemainingDisplayElement> fullscreenTimeRemainingDisplay = MediaControlFullscreenTimeRemainingDisplayElement::create(document); 737 controls->m_fullscreenTimeRemainingDisplay = fullscreenTimeRemainingDisplay.get(); 738 fullscreenTimeDisplayContainer->appendChild(fullscreenTimeRemainingDisplay.release(), ec, AttachLazily); 739 if (ec) 740 return 0; 741 742 controls->m_fullscreenTimeDisplayContainer = fullscreenTimeDisplayContainer.get(); 743 fullscreenTimelineContainer->appendChild(fullscreenTimeDisplayContainer.release(), ec, AttachLazily); 744 if (ec) 745 return 0; 746 747 controls->m_fullscreenTimelineContainer = fullscreenTimelineContainer.get(); 748 panel->appendChild(fullscreenTimelineContainer.release(), ec, AttachLazily); 749 if (ec) 750 return 0; 751 752 RefPtr<MediaControlButtonGroupContainerElement> buttonGroupContainer = MediaControlButtonGroupContainerElement::create(document); 753 754 // FIXME: Only create when needed <http://webkit.org/b/57163> 755 RefPtr<MediaControlFullscreenButtonContainerElement> fullScreenButtonContainer = MediaControlFullscreenButtonContainerElement::create(document); 756 controls->m_fullScreenButtonContainer = fullScreenButtonContainer.get(); 757 RefPtr<MediaControlFullscreenFullscreenButtonElement> fullscreenFullScreenButton = MediaControlFullscreenFullscreenButtonElement::create(document); 758 controls->m_fullscreenFullScreenButton = fullscreenFullScreenButton.get(); 759 fullScreenButtonContainer->appendChild(fullscreenFullScreenButton.release(), ec, AttachLazily); 760 if (ec) 761 return 0; 762 RefPtr<MediaControlFullscreenButtonDividerElement> fullScreenDivider = MediaControlFullscreenButtonDividerElement::create(document); 763 controls->m_fullScreenDivider = fullScreenDivider.get(); 764 fullScreenButtonContainer->appendChild(fullScreenDivider.release(), ec, AttachLazily); 765 if (ec) 766 return 0; 767 buttonGroupContainer->appendChild(fullScreenButtonContainer.release(), ec, AttachLazily); 768 if (ec) 769 return 0; 770 771 RefPtr<MediaControlPlayButtonContainerElement> playButtonContainer = MediaControlPlayButtonContainerElement::create(document); 772 controls->m_playButtonContainer = playButtonContainer.get(); 773 RefPtr<MediaControlFullscreenPlayButtonElement> fullscreenPlayButton = MediaControlFullscreenPlayButtonElement::create(document); 774 controls->m_fullscreenPlayButton = fullscreenPlayButton.get(); 775 playButtonContainer->appendChild(fullscreenPlayButton.release(), ec, AttachLazily); 776 if (ec) 777 return 0; 778 buttonGroupContainer->appendChild(playButtonContainer.release(), ec, AttachLazily); 779 if (ec) 780 return 0; 781 782 RefPtr<MediaControlPlaceholderElement> placeholder = MediaControlPlaceholderElement::create(document); 783 controls->m_placeholder = placeholder.get(); 784 buttonGroupContainer->appendChild(placeholder.release(), ec, AttachLazily); 785 if (ec) 786 return 0; 787 788 controls->m_buttonContainer = buttonGroupContainer.get(); 789 panel->appendChild(buttonGroupContainer.release(), ec, AttachLazily); 790 if (ec) 791 return 0; 792 793 if (document->page()->theme()->supportsClosedCaptioning()) { 794 RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get()); 795 controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get(); 796 panel->appendChild(toggleClosedCaptionsButton.release(), ec, AttachLazily); 797 if (ec) 798 return 0; 799 } 800 801 controls->m_panel = panel.get(); 802 controls->appendChild(panel.release(), ec, AttachLazily); 803 if (ec) 804 return 0; 805 806 controls->m_embeddedPanel = embedPanel.get(); 807 controls->appendChild(embedPanel.release(), ec, AttachLazily); 808 if (ec) 809 return 0; 810 811 return controls.release(); 812} 813 814void MediaControlsBlackBerry::setMediaController(MediaControllerInterface* controller) 815{ 816 if (m_mediaController == controller) 817 return; 818 819 MediaControls::setMediaController(controller); 820 821 if (m_buttonContainer) 822 m_buttonContainer->setMediaController(controller); 823 if (m_timeDisplayContainer) 824 m_timeDisplayContainer->setMediaController(controller); 825 if (m_fullscreenTimeDisplayContainer) 826 m_fullscreenTimeDisplayContainer->setMediaController(controller); 827 if (m_fullscreenPlayButton) 828 m_fullscreenPlayButton->setMediaController(controller); 829 if (m_fullscreenCurrentTimeDisplay) 830 m_fullscreenCurrentTimeDisplay->setMediaController(controller); 831 if (m_fullscreenTimeline) 832 m_fullscreenTimeline->setMediaController(controller); 833 if (m_timeRemainingDisplay) 834 m_timeRemainingDisplay->setMediaController(controller); 835 if (m_fullscreenTimeRemainingDisplay) 836 m_fullscreenTimeRemainingDisplay->setMediaController(controller); 837 if (m_timelineContainer) 838 m_timelineContainer->setMediaController(controller); 839 if (m_fullscreenTimelineContainer) 840 m_fullscreenTimelineContainer->setMediaController(controller); 841 if (m_fullscreenFullScreenButton) 842 m_fullscreenFullScreenButton->setMediaController(controller); 843 if (m_muteButton) 844 m_muteButton->setMediaController(controller); 845 if (m_volumeSliderContainer) 846 m_volumeSliderContainer->setMediaController(controller); 847 if (m_embeddedPanel) 848 m_embeddedPanel->setMediaController(controller); 849 reset(); 850} 851 852void MediaControlsBlackBerry::show() 853{ 854 if (m_isFullscreen) { 855 m_panel->setIsDisplayed(true); 856 m_panel->show(); 857 } else { 858 m_embeddedPanel->setIsDisplayed(true); 859 m_embeddedPanel->show(); 860 } 861} 862 863void MediaControlsBlackBerry::hide() 864{ 865 if (m_isFullscreen) { 866 m_panel->setIsDisplayed(false); 867 m_panel->hide(); 868 } else { 869 m_embeddedPanel->setIsDisplayed(false); 870 m_embeddedPanel->hide(); 871 m_volumeSliderContainer->hide(); 872 } 873} 874 875void MediaControlsBlackBerry::makeOpaque() 876{ 877 if (m_isFullscreen) 878 m_panel->makeOpaque(); 879 else 880 m_embeddedPanel->makeOpaque(); 881} 882 883void MediaControlsBlackBerry::makeTransparent() 884{ 885 if (m_isFullscreen) 886 m_panel->makeTransparent(); 887 else { 888 m_embeddedPanel->makeTransparent(); 889 m_volumeSliderContainer->hide(); 890 } 891} 892 893void MediaControlsBlackBerry::reset() 894{ 895 Page* page = document()->page(); 896 if (!page) 897 return; 898 899 updateStatusDisplay(); 900 901 if (m_fullScreenButton) { 902 if (m_mediaController->supportsFullscreen()) 903 m_fullScreenButton->show(); 904 else 905 m_fullScreenButton->hide(); 906 } 907 if (m_fullscreenFullScreenButton) { 908 if (m_mediaController->supportsFullscreen()) 909 m_fullscreenFullScreenButton->show(); 910 else 911 m_fullscreenFullScreenButton->hide(); 912 } 913 double duration = m_mediaController->duration(); 914 if (std::isfinite(duration) || page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) { 915 double now = m_mediaController->currentTime(); 916 m_timeline->setDuration(duration); 917 m_fullscreenTimeline->setDuration(duration); 918 m_timelineContainer->show(); 919 m_fullscreenTimelineContainer->show(); 920 m_timeline->setPosition(now); 921 m_fullscreenTimeline->setPosition(now); 922 updateCurrentTimeDisplay(); 923 } else { 924 m_timelineContainer->hide(); 925 m_fullscreenTimelineContainer->hide(); 926 } 927 928 if (m_mediaController->hasAudio() || page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) 929 m_muteButton->show(); 930 else 931 m_muteButton->hide(); 932 933 if (m_volumeSlider) 934 m_volumeSlider->setVolume(m_mediaController->volume()); 935 936 if (m_toggleClosedCaptionsButton) { 937 if (m_mediaController->hasClosedCaptions()) 938 m_toggleClosedCaptionsButton->show(); 939 else 940 m_toggleClosedCaptionsButton->hide(); 941 } 942 943 if (m_playButton) 944 m_playButton->updateDisplayType(); 945 946 if (m_fullscreenPlayButton) 947 m_fullscreenPlayButton->updateDisplayType(); 948 949 makeOpaque(); 950} 951 952void MediaControlsBlackBerry::bufferingProgressed() 953{ 954 // We only need to update buffering progress when paused, during normal 955 // playback playbackProgressed() will take care of it. 956 if (m_mediaController->paused()) { 957 double now = m_mediaController->currentTime(); 958 m_timeline->setPosition(now); 959 m_fullscreenTimeline->setPosition(now); 960 } 961} 962 963void MediaControlsBlackBerry::playbackStarted() 964{ 965 double now = m_mediaController->currentTime(); 966 m_playButton->updateDisplayType(); 967 m_fullscreenPlayButton->updateDisplayType(); 968 m_timeline->setPosition(now); 969 m_fullscreenTimeline->setPosition(now); 970 updateCurrentTimeDisplay(); 971 972 if (m_isFullscreen) 973 startHideFullscreenControlsTimer(); 974} 975 976void MediaControlsBlackBerry::playbackProgressed() 977{ 978 double now = m_mediaController->currentTime(); 979 m_timeline->setPosition(now); 980 m_fullscreenTimeline->setPosition(now); 981 updateCurrentTimeDisplay(); 982 983 if (!m_isMouseOverControls && m_mediaController->hasVideo()) 984 makeTransparent(); 985} 986 987void MediaControlsBlackBerry::playbackStopped() 988{ 989 double now = m_mediaController->currentTime(); 990 m_playButton->updateDisplayType(); 991 m_fullscreenPlayButton->updateDisplayType(); 992 m_timeline->setPosition(now); 993 m_fullscreenTimeline->setPosition(now); 994 updateCurrentTimeDisplay(); 995 makeOpaque(); 996 997 stopHideFullscreenControlsTimer(); 998} 999 1000void MediaControlsBlackBerry::updateCurrentTimeDisplay() 1001{ 1002 double now = m_mediaController->currentTime(); 1003 double duration = m_mediaController->duration(); 1004 1005 Page* page = document()->page(); 1006 if (!page) 1007 return; 1008 1009 // Allow the theme to format the time. 1010 m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION); 1011 m_currentTimeDisplay->setCurrentValue(now); 1012 m_fullscreenCurrentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION); 1013 m_fullscreenCurrentTimeDisplay->setCurrentValue(now); 1014 m_timeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); 1015 m_timeRemainingDisplay->setCurrentValue(now - duration); 1016 m_fullscreenTimeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION); 1017 m_fullscreenTimeRemainingDisplay->setCurrentValue(now - duration); 1018} 1019 1020void MediaControlsBlackBerry::reportedError() 1021{ 1022 Page* page = document()->page(); 1023 if (!page) 1024 return; 1025 1026 if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) { 1027 m_timelineContainer->hide(); 1028 m_fullscreenTimelineContainer->hide(); 1029 } 1030 1031 if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart)) 1032 m_muteButton->hide(); 1033 1034 if (m_fullScreenButton) 1035 m_fullScreenButton->hide(); 1036 1037 if (m_fullScreenDivider) 1038 m_fullScreenDivider->hide(); 1039 1040 if (m_fullscreenFullScreenButton) 1041 m_fullscreenFullScreenButton->hide(); 1042 1043 if (m_volumeSliderContainer) 1044 m_volumeSliderContainer->hide(); 1045 1046 if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart)) 1047 m_toggleClosedCaptionsButton->hide(); 1048} 1049 1050void MediaControlsBlackBerry::changedMute() 1051{ 1052 m_muteButton->changedMute(); 1053} 1054 1055void MediaControlsBlackBerry::enteredFullscreen() 1056{ 1057 MediaControls::enteredFullscreen(); 1058 1059 m_panel->setCanBeDragged(true); 1060 m_embeddedPanel->setCanBeDragged(true); 1061 1062 if (m_fullscreenFullScreenButton) 1063 m_fullscreenFullScreenButton->setIsFullscreen(true); 1064} 1065 1066void MediaControlsBlackBerry::exitedFullscreen() 1067{ 1068 m_panel->setCanBeDragged(false); 1069 m_embeddedPanel->setCanBeDragged(false); 1070 1071 if (m_fullscreenFullScreenButton) 1072 m_fullscreenFullScreenButton->setIsFullscreen(false); 1073 1074 // We will keep using the panel, but we want it to go back to the standard position. 1075 // This will matter right away because we use the panel even when not fullscreen. 1076 // And if we reenter fullscreen we also want the panel in the standard position. 1077 m_panel->resetPosition(); 1078 m_embeddedPanel->resetPosition(); 1079 1080 MediaControls::exitedFullscreen(); 1081} 1082 1083void MediaControlsBlackBerry::showVolumeSlider() 1084{ 1085 if (!m_mediaController->hasAudio()) 1086 return; 1087 1088 if (m_volumeSliderContainer) 1089 m_volumeSliderContainer->show(); 1090} 1091 1092void MediaControlsBlackBerry::toggleVolumeSlider() 1093{ 1094 if (!m_mediaController->hasAudio()) 1095 return; 1096 1097 if (m_volumeSliderContainer) { 1098 if (m_volumeSliderContainer->renderer() && m_volumeSliderContainer->renderer()->visibleToHitTesting()) 1099 m_volumeSliderContainer->hide(); 1100 else 1101 m_volumeSliderContainer->show(); 1102 } 1103} 1104 1105bool MediaControlsBlackBerry::shouldHideControls() 1106{ 1107 if (m_isFullscreen) 1108 return !m_panel->hovered(); 1109 return !m_embeddedPanel->hovered(); 1110} 1111} 1112 1113#endif 1114