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 51namespace WebCore { 52 53using namespace HTMLNames; 54 55HTMLMediaElement* 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. 66static const float cSeekRepeatDelay = 0.1f; 67static const float cStepTime = 0.07f; 68static const float cSeekTime = 0.2f; 69 70// ---------------------------- 71 72MediaControlElement::MediaControlElement(HTMLMediaElement* mediaElement) 73 : HTMLDivElement(divTag, mediaElement->document()) 74 , m_mediaElement(mediaElement) 75{ 76} 77 78static const String& displayString() 79{ 80 DEFINE_STATIC_LOCAL(String, s, ("display")); 81 return s; 82} 83 84void MediaControlElement::show() 85{ 86 ExceptionCode ec; 87 // FIXME: Make more efficient <http://webkit.org/b/58157> 88 style()->removeProperty(displayString(), ec); 89} 90 91void 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 101inline MediaControlPanelElement::MediaControlPanelElement(HTMLMediaElement* mediaElement) 102 : MediaControlElement(mediaElement) 103{ 104} 105 106PassRefPtr<MediaControlPanelElement> MediaControlPanelElement::create(HTMLMediaElement* mediaElement) 107{ 108 return adoptRef(new MediaControlPanelElement(mediaElement)); 109} 110 111MediaControlElementType MediaControlPanelElement::displayType() const 112{ 113 return MediaControlsPanel; 114} 115 116const AtomicString& MediaControlPanelElement::shadowPseudoId() const 117{ 118 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-panel")); 119 return id; 120} 121 122// ---------------------------- 123 124inline MediaControlTimelineContainerElement::MediaControlTimelineContainerElement(HTMLMediaElement* mediaElement) 125 : MediaControlElement(mediaElement) 126{ 127} 128 129PassRefPtr<MediaControlTimelineContainerElement> MediaControlTimelineContainerElement::create(HTMLMediaElement* mediaElement) 130{ 131 RefPtr<MediaControlTimelineContainerElement> element = adoptRef(new MediaControlTimelineContainerElement(mediaElement)); 132 element->hide(); 133 return element.release(); 134} 135 136MediaControlElementType MediaControlTimelineContainerElement::displayType() const 137{ 138 return MediaTimelineContainer; 139} 140 141const AtomicString& MediaControlTimelineContainerElement::shadowPseudoId() const 142{ 143 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline-container")); 144 return id; 145} 146 147// ---------------------------- 148 149class RenderMediaVolumeSliderContainer : public RenderBlock { 150public: 151 RenderMediaVolumeSliderContainer(Node*); 152 153private: 154 virtual void layout(); 155}; 156 157RenderMediaVolumeSliderContainer::RenderMediaVolumeSliderContainer(Node* node) 158 : RenderBlock(node) 159{ 160} 161 162void 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 181inline MediaControlVolumeSliderContainerElement::MediaControlVolumeSliderContainerElement(HTMLMediaElement* mediaElement) 182 : MediaControlElement(mediaElement) 183{ 184} 185 186PassRefPtr<MediaControlVolumeSliderContainerElement> MediaControlVolumeSliderContainerElement::create(HTMLMediaElement* mediaElement) 187{ 188 RefPtr<MediaControlVolumeSliderContainerElement> element = adoptRef(new MediaControlVolumeSliderContainerElement(mediaElement)); 189 element->hide(); 190 return element.release(); 191} 192 193RenderObject* MediaControlVolumeSliderContainerElement::createRenderer(RenderArena* arena, RenderStyle*) 194{ 195 return new (arena) RenderMediaVolumeSliderContainer(this); 196} 197 198void 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 215MediaControlElementType MediaControlVolumeSliderContainerElement::displayType() const 216{ 217 return MediaVolumeSliderContainer; 218} 219 220const AtomicString& MediaControlVolumeSliderContainerElement::shadowPseudoId() const 221{ 222 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider-container")); 223 return id; 224} 225 226// ---------------------------- 227 228inline MediaControlStatusDisplayElement::MediaControlStatusDisplayElement(HTMLMediaElement* mediaElement) 229 : MediaControlElement(mediaElement) 230 , m_stateBeingDisplayed(Nothing) 231{ 232} 233 234PassRefPtr<MediaControlStatusDisplayElement> MediaControlStatusDisplayElement::create(HTMLMediaElement* mediaElement) 235{ 236 RefPtr<MediaControlStatusDisplayElement> element = adoptRef(new MediaControlStatusDisplayElement(mediaElement)); 237 element->hide(); 238 return element.release(); 239} 240 241void 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 276MediaControlElementType MediaControlStatusDisplayElement::displayType() const 277{ 278 return MediaStatusDisplay; 279} 280 281const AtomicString& MediaControlStatusDisplayElement::shadowPseudoId() const 282{ 283 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-status-display")); 284 return id; 285} 286 287// ---------------------------- 288 289MediaControlInputElement::MediaControlInputElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) 290 : HTMLInputElement(inputTag, mediaElement->document(), 0, false) 291 , m_mediaElement(mediaElement) 292 , m_displayType(displayType) 293{ 294} 295 296void MediaControlInputElement::show() 297{ 298 ExceptionCode ec; 299 style()->removeProperty(displayString(), ec); 300} 301 302void MediaControlInputElement::hide() 303{ 304 ExceptionCode ec; 305 DEFINE_STATIC_LOCAL(String, none, ("none")); 306 style()->setProperty(displayString(), none, ec); 307} 308 309 310void 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 322inline MediaControlMuteButtonElement::MediaControlMuteButtonElement(HTMLMediaElement* mediaElement, MediaControlElementType displayType) 323 : MediaControlInputElement(mediaElement, displayType) 324{ 325} 326 327void 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 337void MediaControlMuteButtonElement::changedMute() 338{ 339 updateDisplayType(); 340} 341 342void MediaControlMuteButtonElement::updateDisplayType() 343{ 344 setDisplayType(mediaElement()->muted() ? MediaUnMuteButton : MediaMuteButton); 345} 346 347// ---------------------------- 348 349inline MediaControlPanelMuteButtonElement::MediaControlPanelMuteButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) 350 : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) 351 , m_controls(controls) 352{ 353} 354 355PassRefPtr<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 364void MediaControlPanelMuteButtonElement::defaultEventHandler(Event* event) 365{ 366 if (event->type() == eventNames().mouseoverEvent) 367 m_controls->showVolumeSlider(); 368 369 MediaControlMuteButtonElement::defaultEventHandler(event); 370} 371 372const AtomicString& MediaControlPanelMuteButtonElement::shadowPseudoId() const 373{ 374 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-mute-button")); 375 return id; 376} 377 378// ---------------------------- 379 380inline MediaControlVolumeSliderMuteButtonElement::MediaControlVolumeSliderMuteButtonElement(HTMLMediaElement* mediaElement) 381 : MediaControlMuteButtonElement(mediaElement, MediaMuteButton) 382{ 383} 384 385PassRefPtr<MediaControlVolumeSliderMuteButtonElement> MediaControlVolumeSliderMuteButtonElement::create(HTMLMediaElement* mediaElement) 386{ 387 RefPtr<MediaControlVolumeSliderMuteButtonElement> button = adoptRef(new MediaControlVolumeSliderMuteButtonElement(mediaElement)); 388 button->setType("button"); 389 return button.release(); 390} 391 392const 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 400inline MediaControlPlayButtonElement::MediaControlPlayButtonElement(HTMLMediaElement* mediaElement) 401 : MediaControlInputElement(mediaElement, MediaPlayButton) 402{ 403} 404 405PassRefPtr<MediaControlPlayButtonElement> MediaControlPlayButtonElement::create(HTMLMediaElement* mediaElement) 406{ 407 RefPtr<MediaControlPlayButtonElement> button = adoptRef(new MediaControlPlayButtonElement(mediaElement)); 408 button->setType("button"); 409 return button.release(); 410} 411 412void 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 422void MediaControlPlayButtonElement::updateDisplayType() 423{ 424 setDisplayType(mediaElement()->canPlay() ? MediaPlayButton : MediaPauseButton); 425} 426 427const AtomicString& MediaControlPlayButtonElement::shadowPseudoId() const 428{ 429 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button")); 430 return id; 431} 432 433// ---------------------------- 434 435inline 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 443void 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 473void 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 481void 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 492inline MediaControlSeekForwardButtonElement::MediaControlSeekForwardButtonElement(HTMLMediaElement* mediaElement) 493 : MediaControlSeekButtonElement(mediaElement, MediaSeekForwardButton) 494{ 495} 496 497PassRefPtr<MediaControlSeekForwardButtonElement> MediaControlSeekForwardButtonElement::create(HTMLMediaElement* mediaElement) 498{ 499 RefPtr<MediaControlSeekForwardButtonElement> button = adoptRef(new MediaControlSeekForwardButtonElement(mediaElement)); 500 button->setType("button"); 501 return button.release(); 502} 503 504const AtomicString& MediaControlSeekForwardButtonElement::shadowPseudoId() const 505{ 506 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-forward-button")); 507 return id; 508} 509 510// ---------------------------- 511 512inline MediaControlSeekBackButtonElement::MediaControlSeekBackButtonElement(HTMLMediaElement* mediaElement) 513 : MediaControlSeekButtonElement(mediaElement, MediaSeekBackButton) 514{ 515} 516 517PassRefPtr<MediaControlSeekBackButtonElement> MediaControlSeekBackButtonElement::create(HTMLMediaElement* mediaElement) 518{ 519 RefPtr<MediaControlSeekBackButtonElement> button = adoptRef(new MediaControlSeekBackButtonElement(mediaElement)); 520 button->setType("button"); 521 return button.release(); 522} 523 524const AtomicString& MediaControlSeekBackButtonElement::shadowPseudoId() const 525{ 526 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-seek-back-button")); 527 return id; 528} 529 530// ---------------------------- 531 532inline MediaControlRewindButtonElement::MediaControlRewindButtonElement(HTMLMediaElement* element) 533 : MediaControlInputElement(element, MediaRewindButton) 534{ 535} 536 537PassRefPtr<MediaControlRewindButtonElement> MediaControlRewindButtonElement::create(HTMLMediaElement* mediaElement) 538{ 539 RefPtr<MediaControlRewindButtonElement> button = adoptRef(new MediaControlRewindButtonElement(mediaElement)); 540 button->setType("button"); 541 return button.release(); 542} 543 544void 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 553const AtomicString& MediaControlRewindButtonElement::shadowPseudoId() const 554{ 555 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-rewind-button")); 556 return id; 557} 558 559// ---------------------------- 560 561inline MediaControlReturnToRealtimeButtonElement::MediaControlReturnToRealtimeButtonElement(HTMLMediaElement* mediaElement) 562 : MediaControlInputElement(mediaElement, MediaReturnToRealtimeButton) 563{ 564} 565 566PassRefPtr<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 574void MediaControlReturnToRealtimeButtonElement::defaultEventHandler(Event* event) 575{ 576 if (event->type() == eventNames().clickEvent) { 577 mediaElement()->returnToRealtime(); 578 event->setDefaultHandled(); 579 } 580 HTMLInputElement::defaultEventHandler(event); 581} 582 583const 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 591inline MediaControlToggleClosedCaptionsButtonElement::MediaControlToggleClosedCaptionsButtonElement(HTMLMediaElement* mediaElement) 592 : MediaControlInputElement(mediaElement, MediaShowClosedCaptionsButton) 593{ 594} 595 596PassRefPtr<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 604void 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 616void MediaControlToggleClosedCaptionsButtonElement::updateDisplayType() 617{ 618 setDisplayType(mediaElement()->closedCaptionsVisible() ? MediaHideClosedCaptionsButton : MediaShowClosedCaptionsButton); 619} 620 621const 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 629MediaControlTimelineElement::MediaControlTimelineElement(HTMLMediaElement* mediaElement, MediaControls* controls) 630 : MediaControlInputElement(mediaElement, MediaSlider) 631 , m_controls(controls) 632{ 633} 634 635PassRefPtr<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 645void 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 692void MediaControlTimelineElement::setPosition(float currentTime) 693{ 694 setValue(String::number(currentTime)); 695} 696 697void MediaControlTimelineElement::setDuration(float duration) 698{ 699 setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0)); 700} 701 702 703const AtomicString& MediaControlTimelineElement::shadowPseudoId() const 704{ 705 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-timeline")); 706 return id; 707} 708 709// ---------------------------- 710 711inline MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(HTMLMediaElement* mediaElement) 712 : MediaControlInputElement(mediaElement, MediaVolumeSlider) 713{ 714} 715 716PassRefPtr<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 726void 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 748void MediaControlVolumeSliderElement::setVolume(float volume) 749{ 750 if (value().toFloat() != volume) 751 setValue(String::number(volume)); 752} 753 754const AtomicString& MediaControlVolumeSliderElement::shadowPseudoId() const 755{ 756 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-volume-slider")); 757 return id; 758} 759 760// ---------------------------- 761 762inline MediaControlFullscreenVolumeSliderElement::MediaControlFullscreenVolumeSliderElement(HTMLMediaElement* mediaElement) 763 : MediaControlVolumeSliderElement(mediaElement) 764{ 765} 766 767PassRefPtr<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 777const AtomicString& MediaControlFullscreenVolumeSliderElement::shadowPseudoId() const 778{ 779 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-volume-slider")); 780 return id; 781} 782 783// ---------------------------- 784 785inline MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(HTMLMediaElement* mediaElement, MediaControls* controls) 786 : MediaControlInputElement(mediaElement, MediaFullscreenButton) 787 , m_controls(controls) 788{ 789} 790 791PassRefPtr<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 801void 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 826const AtomicString& MediaControlFullscreenButtonElement::shadowPseudoId() const 827{ 828 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button")); 829 return id; 830} 831 832// ---------------------------- 833 834inline MediaControlFullscreenVolumeMinButtonElement::MediaControlFullscreenVolumeMinButtonElement(HTMLMediaElement* mediaElement) 835 : MediaControlInputElement(mediaElement, MediaUnMuteButton) 836{ 837} 838 839PassRefPtr<MediaControlFullscreenVolumeMinButtonElement> MediaControlFullscreenVolumeMinButtonElement::create(HTMLMediaElement* mediaElement) 840{ 841 RefPtr<MediaControlFullscreenVolumeMinButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMinButtonElement(mediaElement)); 842 button->setType("button"); 843 return button.release(); 844} 845 846void 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 856const 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 864inline MediaControlFullscreenVolumeMaxButtonElement::MediaControlFullscreenVolumeMaxButtonElement(HTMLMediaElement* mediaElement) 865: MediaControlInputElement(mediaElement, MediaMuteButton) 866{ 867} 868 869PassRefPtr<MediaControlFullscreenVolumeMaxButtonElement> MediaControlFullscreenVolumeMaxButtonElement::create(HTMLMediaElement* mediaElement) 870{ 871 RefPtr<MediaControlFullscreenVolumeMaxButtonElement> button = adoptRef(new MediaControlFullscreenVolumeMaxButtonElement(mediaElement)); 872 button->setType("button"); 873 return button.release(); 874} 875 876void 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 886const 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 894class RenderMediaControlTimeDisplay : public RenderFlexibleBox { 895public: 896 RenderMediaControlTimeDisplay(Node*); 897 898private: 899 virtual void layout(); 900}; 901 902RenderMediaControlTimeDisplay::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. 909static const int minWidthToDisplayTimeDisplays = 45 + 100 + 45; 910 911void 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 922inline MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(HTMLMediaElement* mediaElement) 923 : MediaControlElement(mediaElement) 924 , m_currentValue(0) 925{ 926} 927 928void MediaControlTimeDisplayElement::setCurrentValue(float time) 929{ 930 m_currentValue = time; 931} 932 933RenderObject* MediaControlTimeDisplayElement::createRenderer(RenderArena* arena, RenderStyle*) 934{ 935 return new (arena) RenderMediaControlTimeDisplay(this); 936} 937 938// ---------------------------- 939 940PassRefPtr<MediaControlTimeRemainingDisplayElement> MediaControlTimeRemainingDisplayElement::create(HTMLMediaElement* mediaElement) 941{ 942 return adoptRef(new MediaControlTimeRemainingDisplayElement(mediaElement)); 943} 944 945MediaControlTimeRemainingDisplayElement::MediaControlTimeRemainingDisplayElement(HTMLMediaElement* mediaElement) 946 : MediaControlTimeDisplayElement(mediaElement) 947{ 948} 949 950MediaControlElementType MediaControlTimeRemainingDisplayElement::displayType() const 951{ 952 return MediaTimeRemainingDisplay; 953} 954 955const AtomicString& MediaControlTimeRemainingDisplayElement::shadowPseudoId() const 956{ 957 DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-remaining-display")); 958 return id; 959} 960 961// ---------------------------- 962 963PassRefPtr<MediaControlCurrentTimeDisplayElement> MediaControlCurrentTimeDisplayElement::create(HTMLMediaElement* mediaElement) 964{ 965 return adoptRef(new MediaControlCurrentTimeDisplayElement(mediaElement)); 966} 967 968MediaControlCurrentTimeDisplayElement::MediaControlCurrentTimeDisplayElement(HTMLMediaElement* mediaElement) 969 : MediaControlTimeDisplayElement(mediaElement) 970{ 971} 972 973MediaControlElementType MediaControlCurrentTimeDisplayElement::displayType() const 974{ 975 return MediaCurrentTimeDisplay; 976} 977 978const 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