1 /* 2 * Copyright (C) 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 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include "config.h" 30 31 #if ENABLE(VIDEO) 32 33 #include "MediaControlElements.h" 34 35 #include "CSSStyleSelector.h" 36 #include "EventNames.h" 37 #include "FloatConversion.h" 38 #include "Frame.h" 39 #include "HTMLNames.h" 40 #include "LocalizedStrings.h" 41 #include "MediaControls.h" 42 #include "MouseEvent.h" 43 #include "Page.h" 44 #include "RenderFlexibleBox.h" 45 #include "RenderMedia.h" 46 #include "RenderSlider.h" 47 #include "RenderTheme.h" 48 #include "RenderView.h" 49 #include "Settings.h" 50 51 namespace WebCore { 52 53 using namespace HTMLNames; 54 55 HTMLMediaElement* toParentMediaElement(RenderObject* o) 56 { 57 Node* node = o->node(); 58 Node* mediaNode = node ? node->shadowAncestorNode() : 0; 59 if (!mediaNode || (!mediaNode->hasTagName(HTMLNames::videoTag) && !mediaNode->hasTagName(HTMLNames::audioTag))) 60 return 0; 61 62 return static_cast<HTMLMediaElement*>(mediaNode); 63 } 64 65 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in. 66 static const float cSeekRepeatDelay = 0.1f; 67 static const float cStepTime = 0.07f; 68 static const float cSeekTime = 0.2f; 69 70 // ---------------------------- 71 72 MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement) 73 : HTMLDivElement(divTag, mediaElement->document()) 74 , m_mediaElement(mediaElement) 75 { 76 } 77 78 static const String& displayString() 79 { 80 DEFINE_STATIC_LOCAL(String, s, ("display")); 81 return s; 82 } 83 84 void MediaControlElement::show() 85 { 86 ExceptionCode ec; 87 // FIXME: Make more efficient <http://webkit.org/b/58157> 88 style()->removeProperty(displayString(), ec); 89 } 90 91 void MediaControlElement::hide() 92 { 93 ExceptionCode ec; 94 // FIXME: Make more efficient <http://webkit.org/b/58157> 95 DEFINE_STATIC_LOCAL(String, none, ("none")); 96 style()->setProperty(displayString(), none, ec); 97 } 98 99 // ---------------------------- 100 101 inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement) 102 : MediaControlElement(mediaElement) 103 { 104 } 105 106 PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement) 107 { 108 return adoptRef(new MediaControlPanelElement(mediaElement)); 109 } 110 111 MediaControlElementType MediaControlPanelElement::displayType() const 112 { 113 return MediaControlsPanel; 114 } 115 116 const AtomicString& MediaControlPanelElement::shadowPseudoId() const 117 { 118 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel")); 119 return id; 120 } 121 122 // ---------------------------- 123 124 inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement) 125 : MediaControlElement(mediaElement) 126 { 127 } 128 129 PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement) 130 { 131 RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(mediaElement)); 132 element->hide(); 133 return element.release(); 134 } 135 136 MediaControlElementType MediaControlTimelineContainerElement::displayType() const 137 { 138 return MediaTimelineContainer; 139 } 140 141 const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const 142 { 143 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container")); 144 return id; 145 } 146 147 // ---------------------------- 148 149 class RenderMediaVolumeSliderContainer : public RenderBlock { 150 public: 151 RenderMediaVolumeSliderContainer(Node*); 152 153 private: 154 virtual void layout(); 155 }; 156 157 RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node) 158 : RenderBlock(node) 159 { 160 } 161 162 void RenderMediaVolumeSliderContainer::layout() 163 { 164 RenderBlock::layout(); 165 if (style()->display() == NONE || !previousSibling() || !previousSibling()->isBox()) 166 return; 167 168 RenderBox* buttonBox = toRenderBox(previousSibling()); 169 170 if (view()) 171 view()->disableLayoutState(); 172 173 IntPoint offset = theme()->volumeSliderOffsetFromMuteButton(buttonBox, IntSize(width(), height())); 174 setX(offset.x() + buttonBox->offsetLeft()); 175 setY(offset.y() + buttonBox->offsetTop()); 176 177 if (view()) 178 view()->enableLayoutState(); 179 } 180 181 inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement) 182 : MediaControlElement(mediaElement) 183 { 184 } 185 186 PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement) 187 { 188 RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement)); 189 element->hide(); 190 return element.release(); 191 } 192 193 RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*) 194 { 195 return new (arena) RenderMediaVolumeSliderContainer(this); 196 } 197 198 void MediaControlVolumeSliderContainerElement::defaultEventHandler(Event* event) 199 { 200 if (!event->isMouseEvent() || event->type() != eventNames().mouseoutEvent) 201 return; 202 203 // Poor man's mouseleave event detection. 204 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); 205 if (!mouseEvent->relatedTarget() || !mouseEvent->relatedTarget()->toNode()) 206 return; 207 208 if (this->containsIncludingShadowDOM(mouseEvent->relatedTarget()->toNode())) 209 return; 210 211 hide(); 212 } 213 214 215 MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const 216 { 217 return MediaVolumeSliderContainer; 218 } 219 220 const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const 221 { 222 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container")); 223 return id; 224 } 225 226 // ---------------------------- 227 228 inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement) 229 : MediaControlElement(mediaElement) 230 , m_stateBeingDisplayed(Nothing) 231 { 232 } 233 234 PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement) 235 { 236 RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(mediaElement)); 237 element->hide(); 238 return element.release(); 239 } 240 241 void MediaControlStatusDisplayElement::update() 242 { 243 // Get the new state that we'll have to display. 244 StateBeingDisplayed newStateToDisplay = Nothing; 245 246 if (mediaElement()->readyState() != HTMLMediaElement::HAVE_ENOUGH_DATA && !mediaElement()->currentSrc().isEmpty()) 247 newStateToDisplay = Loading; 248 else if (mediaElement()->movieLoadType() == MediaPlayer::LiveStream) 249 newStateToDisplay = LiveBroadcast; 250 251 if (newStateToDisplay == m_stateBeingDisplayed) 252 return; 253 254 ExceptionCode e; 255 256 if (m_stateBeingDisplayed == Nothing) 257 show(); 258 else if (newStateToDisplay == Nothing) 259 hide(); 260 261 m_stateBeingDisplayed = newStateToDisplay; 262 263 switch (m_stateBeingDisplayed) { 264 case Nothing: 265 setInnerText("", e); 266 break; 267 case Loading: 268 setInnerText(mediaElementLoadingStateText(), e); 269 break; 270 case LiveBroadcast: 271 setInnerText(mediaElementLiveBroadcastStateText(), e); 272 break; 273 } 274 } 275 276 MediaControlElementType MediaControlStatusDisplayElement::displayType() const 277 { 278 return MediaStatusDisplay; 279 } 280 281 const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const 282 { 283 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display")); 284 return id; 285 } 286 287 // ---------------------------- 288 289 MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) 290 : HTMLInputElement(inputTag, mediaElement->document(), 0, false) 291 , m_mediaElement(mediaElement) 292 , m_displayType(displayType) 293 { 294 } 295 296 void MediaControlInputElement::show() 297 { 298 ExceptionCode ec; 299 style()->removeProperty(displayString(), ec); 300 } 301 302 void MediaControlInputElement::hide() 303 { 304 ExceptionCode ec; 305 DEFINE_STATIC_LOCAL(String, none, ("none")); 306 style()->setProperty(displayString(), none, ec); 307 } 308 309 310 void MediaControlInputElement::setDisplayType(MediaControlElementType displayType) 311 { 312 if (displayType == m_displayType) 313 return; 314 315 m_displayType = displayType; 316 if (RenderObject* object = renderer()) 317 object->repaint(); 318 } 319 320 // ---------------------------- 321 322 inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) 323 : MediaControlInputElement(mediaElement, displayType) 324 { 325 } 326 327 void MediaControlMuteButtonElement::defaultEventHandler(Event* event) 328 { 329 if (event->type() == eventNames().clickEvent) { 330 mediaElement()->setMuted(!mediaElement()->muted()); 331 event->setDefaultHandled(); 332 } 333 334 HTMLInputElement::defaultEventHandler(event); 335 } 336 337 void MediaControlMuteButtonElement::changedMute() 338 { 339 updateDisplayType(); 340 } 341 342 void MediaControlMuteButtonElement::updateDisplayType() 343 { 344 setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); 345 } 346 347 // ---------------------------- 348 349 inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) 350 : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) 351 , m_controls(controls) 352 { 353 } 354 355 PassRefPtr<MediaControlPanelMuteButtonElement> MediaControlPanelMuteButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) 356 { 357 ASSERT(controls); 358 359 RefPtr<MediaControlPanelMuteButtonElement> button = adoptRef(new MediaControlPanelMuteButtonElement(mediaElement, controls)); 360 button->setType("button"); 361 return button.release(); 362 } 363 364 void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event) 365 { 366 if (event->type() == eventNames().mouseoverEvent) 367 m_controls->showVolumeSlider(); 368 369 MediaControlMuteButtonElement::defaultEventHandler(event); 370 } 371 372 const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const 373 { 374 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); 375 return id; 376 } 377 378 // ---------------------------- 379 380 inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) 381 : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) 382 { 383 } 384 385 PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement) 386 { 387 RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement)); 388 button->setType("button"); 389 return button.release(); 390 } 391 392 const AtomicString& MediaControlVolumeSliderMuteButtonElement::shadowPseudoId() const 393 { 394 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-mute-button")); 395 return id; 396 } 397 398 // ---------------------------- 399 400 inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement) 401 : MediaControlInputElement(mediaElement, MediaPlayButton) 402 { 403 } 404 405 PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement) 406 { 407 RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement)); 408 button->setType("button"); 409 return button.release(); 410 } 411 412 void MediaControlPlayButtonElement::defaultEventHandler(Event* event) 413 { 414 if (event->type() == eventNames().clickEvent) { 415 mediaElement()->togglePlayState(); 416 updateDisplayType(); 417 event->setDefaultHandled(); 418 } 419 HTMLInputElement::defaultEventHandler(event); 420 } 421 422 void MediaControlPlayButtonElement::updateDisplayType() 423 { 424 setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton); 425 } 426 427 const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const 428 { 429 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button")); 430 return id; 431 } 432 433 // ---------------------------- 434 435 inline MediaControlSeekButtonElement::MediaControlSeekButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) 436 : MediaControlInputElement(mediaElement, displayType) 437 , m_seeking(false) 438 , m_capturing(false) 439 , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired) 440 { 441 } 442 443 void MediaControlSeekButtonElement::defaultEventHandler(Event* event) 444 { 445 if (event->type() == eventNames().mousedownEvent) { 446 if (Frame* frame = document()->frame()) { 447 m_capturing = true; 448 frame->eventHandler()->setCapturingMouseEventsNode(this); 449 } 450 mediaElement()->pause(event->fromUserGesture()); 451 m_seekTimer.startRepeating(cSeekRepeatDelay); 452 event->setDefaultHandled(); 453 } else if (event->type() == eventNames().mouseupEvent) { 454 if (m_capturing) 455 if (Frame* frame = document()->frame()) { 456 m_capturing = false; 457 frame->eventHandler()->setCapturingMouseEventsNode(0); 458 } 459 ExceptionCode ec; 460 if (m_seeking || m_seekTimer.isActive()) { 461 if (!m_seeking) { 462 float stepTime = isForwardButton() ? cStepTime : -cStepTime; 463 mediaElement()->setCurrentTime(mediaElement()->currentTime() + stepTime, ec); 464 } 465 m_seekTimer.stop(); 466 m_seeking = false; 467 event->setDefaultHandled(); 468 } 469 } 470 HTMLInputElement::defaultEventHandler(event); 471 } 472 473 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*) 474 { 475 ExceptionCode ec; 476 m_seeking = true; 477 float seekTime = isForwardButton() ? cSeekTime : -cSeekTime; 478 mediaElement()->setCurrentTime(mediaElement()->currentTime() + seekTime, ec); 479 } 480 481 void MediaControlSeekButtonElement::detach() 482 { 483 if (m_capturing) { 484 if (Frame* frame = document()->frame()) 485 frame->eventHandler()->setCapturingMouseEventsNode(0); 486 } 487 MediaControlInputElement::detach(); 488 } 489 490 // ---------------------------- 491 492 inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement) 493 : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton) 494 { 495 } 496 497 PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement) 498 { 499 RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement)); 500 button->setType("button"); 501 return button.release(); 502 } 503 504 const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const 505 { 506 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button")); 507 return id; 508 } 509 510 // ---------------------------- 511 512 inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement) 513 : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton) 514 { 515 } 516 517 PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement) 518 { 519 RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement)); 520 button->setType("button"); 521 return button.release(); 522 } 523 524 const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const 525 { 526 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button")); 527 return id; 528 } 529 530 // ---------------------------- 531 532 inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element) 533 : MediaControlInputElement(element, MediaRewindButton) 534 { 535 } 536 537 PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement) 538 { 539 RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement)); 540 button->setType("button"); 541 return button.release(); 542 } 543 544 void MediaControlRewindButtonElement::defaultEventHandler(Event* event) 545 { 546 if (event->type() == eventNames().clickEvent) { 547 mediaElement()->rewind(30); 548 event->setDefaultHandled(); 549 } 550 HTMLInputElement::defaultEventHandler(event); 551 } 552 553 const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const 554 { 555 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button")); 556 return id; 557 } 558 559 // ---------------------------- 560 561 inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement) 562 : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton) 563 { 564 } 565 566 PassRefPtr<MediaControlReturnToRealtimeButtonElement> MediaControlReturnToRealtimeButtonElement::create(HTMLMediaElement* mediaElement) 567 { 568 RefPtr<MediaControlReturnToRealtimeButtonElement> button = adoptRef(new MediaControlReturnToRealtimeButtonElement(mediaElement)); 569 button->setType("button"); 570 button->hide(); 571 return button.release(); 572 } 573 574 void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event) 575 { 576 if (event->type() == eventNames().clickEvent) { 577 mediaElement()->returnToRealtime(); 578 event->setDefaultHandled(); 579 } 580 HTMLInputElement::defaultEventHandler(event); 581 } 582 583 const AtomicString& MediaControlReturnToRealtimeButtonElement::shadowPseudoId() const 584 { 585 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-return-to-realtime-button")); 586 return id; 587 } 588 589 // ---------------------------- 590 591 inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement) 592 : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton) 593 { 594 } 595 596 PassRefPtr<MediaControlToggleClosedCaptionsButtonElement> MediaControlToggleClosedCaptionsButtonElement::create(HTMLMediaElement* mediaElement) 597 { 598 RefPtr<MediaControlToggleClosedCaptionsButtonElement> button = adoptRef(new MediaControlToggleClosedCaptionsButtonElement(mediaElement)); 599 button->setType("button"); 600 button->hide(); 601 return button.release(); 602 } 603 604 void MediaControlToggleClosedCaptionsButtonElement::defaultEventHandler(Event* event) 605 { 606 if (event->type() == eventNames().clickEvent) { 607 mediaElement()->setClosedCaptionsVisible(!mediaElement()->closedCaptionsVisible()); 608 setChecked(mediaElement()->closedCaptionsVisible()); 609 updateDisplayType(); 610 event->setDefaultHandled(); 611 } 612 613 HTMLInputElement::defaultEventHandler(event); 614 } 615 616 void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() 617 { 618 setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); 619 } 620 621 const AtomicString& MediaControlToggleClosedCaptionsButtonElement::shadowPseudoId() const 622 { 623 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-toggle-closed-captions-button")); 624 return id; 625 } 626 627 // ---------------------------- 628 629 MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement, MediaControls* controls) 630 : MediaControlInputElement(mediaElement, MediaSlider) 631 , m_controls(controls) 632 { 633 } 634 635 PassRefPtr<MediaControlTimelineElement> MediaControlTimelineElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) 636 { 637 ASSERT(controls); 638 639 RefPtr<MediaControlTimelineElement> timeline = adoptRef(new MediaControlTimelineElement(mediaElement, controls)); 640 timeline->setType("range"); 641 timeline->setAttribute(precisionAttr, "float"); 642 return timeline.release(); 643 } 644 645 void MediaControlTimelineElement::defaultEventHandler(Event* event) 646 { 647 // Left button is 0. Rejects mouse events not from left button. 648 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) 649 return; 650 651 if (!attached()) 652 return; 653 654 if (event->type() == eventNames().mousedownEvent) 655 mediaElement()->beginScrubbing(); 656 657 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 658 if (event->type() == eventNames().touchstartEvent) 659 mediaElement()->beginScrubbing(); 660 #endif 661 662 MediaControlInputElement::defaultEventHandler(event); 663 664 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) 665 return; 666 667 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 668 if (event->type() == eventNames().touchmoveEvent || event->type() == eventNames().touchcancelEvent) 669 return; 670 #endif 671 672 float time = narrowPrecisionToFloat(value().toDouble()); 673 if (time != mediaElement()->currentTime()) { 674 // FIXME: This is fired 3 times on every click. We should not be doing that <http:/webkit.org/b/58160>. 675 ExceptionCode ec; 676 mediaElement()->setCurrentTime(time, ec); 677 } 678 679 RenderSlider* slider = toRenderSlider(renderer()); 680 if (slider && slider->inDragMode()) 681 m_controls->updateTimeDisplay(); 682 683 if (event->type() == eventNames().mouseupEvent) 684 mediaElement()->endScrubbing(); 685 686 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS) 687 if (event->type() == eventNames().touchendEvent) 688 mediaElement()->endScrubbing(); 689 #endif 690 } 691 692 void MediaControlTimelineElement::setPosition(float currentTime) 693 { 694 setValue(String::number(currentTime)); 695 } 696 697 void MediaControlTimelineElement::setDuration(float duration) 698 { 699 setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0)); 700 } 701 702 703 const AtomicString& MediaControlTimelineElement::shadowPseudoId() const 704 { 705 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline")); 706 return id; 707 } 708 709 // ---------------------------- 710 711 inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement) 712 : MediaControlInputElement(mediaElement, MediaVolumeSlider) 713 { 714 } 715 716 PassRefPtr<MediaControlVolumeSliderElement> MediaControlVolumeSliderElement::create(HTMLMediaElement* mediaElement) 717 { 718 RefPtr<MediaControlVolumeSliderElement> slider = adoptRef(new MediaControlVolumeSliderElement(mediaElement)); 719 slider->setType("range"); 720 slider->setAttribute(precisionAttr, "float"); 721 slider->setAttribute(maxAttr, "1"); 722 slider->setAttribute(valueAttr, String::number(mediaElement->volume())); 723 return slider.release(); 724 } 725 726 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) 727 { 728 // Left button is 0. Rejects mouse events not from left button. 729 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) 730 return; 731 732 if (!attached()) 733 return; 734 735 MediaControlInputElement::defaultEventHandler(event); 736 737 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) 738 return; 739 740 float volume = narrowPrecisionToFloat(value().toDouble()); 741 if (volume != mediaElement()->volume()) { 742 ExceptionCode ec = 0; 743 mediaElement()->setVolume(volume, ec); 744 ASSERT(!ec); 745 } 746 } 747 748 void MediaControlVolumeSliderElement::setVolume(float volume) 749 { 750 if (value().toFloat() != volume) 751 setValue(String::number(volume)); 752 } 753 754 const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const 755 { 756 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider")); 757 return id; 758 } 759 760 // ---------------------------- 761 762 inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement) 763 : MediaControlVolumeSliderElement(mediaElement) 764 { 765 } 766 767 PassRefPtr<MediaControlFullscreenVolumeSliderElement> MediaControlFullscreenVolumeSliderElement::create(HTMLMediaElement* mediaElement) 768 { 769 RefPtr<MediaControlFullscreenVolumeSliderElement> slider = adoptRef(new MediaControlFullscreenVolumeSliderElement(mediaElement)); 770 slider->setType("range"); 771 slider->setAttribute(precisionAttr, "float"); 772 slider->setAttribute(maxAttr, "1"); 773 slider->setAttribute(valueAttr, String::number(mediaElement->volume())); 774 return slider.release(); 775 } 776 777 const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const 778 { 779 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider")); 780 return id; 781 } 782 783 // ---------------------------- 784 785 inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) 786 : MediaControlInputElement(mediaElement, MediaFullscreenButton) 787 , m_controls(controls) 788 { 789 } 790 791 PassRefPtr<MediaControlFullscreenButtonElement> MediaControlFullscreenButtonElement::create(HTMLMediaElement* mediaElement, MediaControls* controls) 792 { 793 ASSERT(controls); 794 795 RefPtr<MediaControlFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenButtonElement(mediaElement, controls)); 796 button->setType("button"); 797 button->hide(); 798 return button.release(); 799 } 800 801 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event) 802 { 803 if (event->type() == eventNames().clickEvent) { 804 #if ENABLE(FULLSCREEN_API) 805 // Only use the new full screen API if the fullScreenEnabled setting has 806 // been explicitly enabled. Otherwise, use the old fullscreen API. This 807 // allows apps which embed a WebView to retain the existing full screen 808 // video implementation without requiring them to implement their own full 809 // screen behavior. 810 if (document()->settings() && document()->settings()->fullScreenEnabled()) { 811 if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == mediaElement()) { 812 document()->webkitCancelFullScreen(); 813 m_controls->exitedFullscreen(); 814 } else { 815 mediaElement()->webkitRequestFullScreen(0); 816 m_controls->enteredFullscreen(); 817 } 818 } else 819 #endif 820 mediaElement()->enterFullscreen(); 821 event->setDefaultHandled(); 822 } 823 HTMLInputElement::defaultEventHandler(event); 824 } 825 826 const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const 827 { 828 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button")); 829 return id; 830 } 831 832 // ---------------------------- 833 834 inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement) 835 : MediaControlInputElement(mediaElement, MediaUnMuteButton) 836 { 837 } 838 839 PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement) 840 { 841 RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement)); 842 button->setType("button"); 843 return button.release(); 844 } 845 846 void MediaControlFullscreenVolumeMinButtonElement::defaultEventHandler(Event* event) 847 { 848 if (event->type() == eventNames().clickEvent) { 849 ExceptionCode code = 0; 850 mediaElement()->setVolume(0, code); 851 event->setDefaultHandled(); 852 } 853 HTMLInputElement::defaultEventHandler(event); 854 } 855 856 const AtomicString& MediaControlFullscreenVolumeMinButtonElement::shadowPseudoId() const 857 { 858 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-min-button")); 859 return id; 860 } 861 862 // ---------------------------- 863 864 inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement) 865 : MediaControlInputElement(mediaElement, MediaMuteButton) 866 { 867 } 868 869 PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement) 870 { 871 RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement)); 872 button->setType("button"); 873 return button.release(); 874 } 875 876 void MediaControlFullscreenVolumeMaxButtonElement::defaultEventHandler(Event* event) 877 { 878 if (event->type() == eventNames().clickEvent) { 879 ExceptionCode code = 0; 880 mediaElement()->setVolume(1, code); 881 event->setDefaultHandled(); 882 } 883 HTMLInputElement::defaultEventHandler(event); 884 } 885 886 const AtomicString& MediaControlFullscreenVolumeMaxButtonElement::shadowPseudoId() const 887 { 888 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-max-button")); 889 return id; 890 } 891 892 // ---------------------------- 893 894 class RenderMediaControlTimeDisplay : public RenderFlexibleBox { 895 public: 896 RenderMediaControlTimeDisplay(Node*); 897 898 private: 899 virtual void layout(); 900 }; 901 902 RenderMediaControlTimeDisplay::RenderMediaControlTimeDisplay(Node* node) 903 : RenderFlexibleBox(node) 904 { 905 } 906 907 // We want the timeline slider to be at least 100 pixels wide. 908 // FIXME: Eliminate hard-coded widths altogether. 909 static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45; 910 911 void RenderMediaControlTimeDisplay::layout() 912 { 913 RenderFlexibleBox::layout(); 914 RenderBox* timelineContainerBox = parentBox(); 915 while (timelineContainerBox && timelineContainerBox->isAnonymous()) 916 timelineContainerBox = timelineContainerBox->parentBox(); 917 918 if (timelineContainerBox && timelineContainerBox->width() < minWidthToDisplayTimeDisplays) 919 setWidth(0); 920 } 921 922 inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement) 923 : MediaControlElement(mediaElement) 924 , m_currentValue(0) 925 { 926 } 927 928 void MediaControlTimeDisplayElement::setCurrentValue(float time) 929 { 930 m_currentValue = time; 931 } 932 933 RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*) 934 { 935 return new (arena) RenderMediaControlTimeDisplay(this); 936 } 937 938 // ---------------------------- 939 940 PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement) 941 { 942 return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement)); 943 } 944 945 MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement) 946 : MediaControlTimeDisplayElement(mediaElement) 947 { 948 } 949 950 MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const 951 { 952 return MediaTimeRemainingDisplay; 953 } 954 955 const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const 956 { 957 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display")); 958 return id; 959 } 960 961 // ---------------------------- 962 963 PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement) 964 { 965 return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement)); 966 } 967 968 MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement) 969 : MediaControlTimeDisplayElement(mediaElement) 970 { 971 } 972 973 MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const 974 { 975 return MediaCurrentTimeDisplay; 976 } 977 978 const AtomicString& MediaControlCurrentTimeDisplayElement::shadowPseudoId() const 979 { 980 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-current-time-display")); 981 return id; 982 } 983 984 } // namespace WebCore 985 986 #endif // ENABLE(VIDEO) 987