1/* 2 * Copyright (C) 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 3 * Copyright (C) 2012 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 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 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30#include "config.h" 31 32#if ENABLE(VIDEO) 33#include "MediaControlElementTypes.h" 34 35#include "CSSValueKeywords.h" 36#include "ExceptionCodePlaceholder.h" 37#include "HTMLNames.h" 38#include "MouseEvent.h" 39#include "RenderMedia.h" 40#include "RenderMediaControlElements.h" 41#include "StylePropertySet.h" 42 43namespace WebCore { 44 45using namespace HTMLNames; 46 47class Event; 48 49// FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in. 50static const double cSkipRepeatDelay = 0.1; 51static const double cSkipTime = 0.2; 52static const double cScanRepeatDelay = 1.5; 53static const double cScanMaximumRate = 8; 54 55HTMLMediaElement* toParentMediaElement(Node* node) 56{ 57 if (!node) 58 return 0; 59 Node* mediaNode = node->shadowHost(); 60 if (!mediaNode) 61 mediaNode = node; 62 if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement()) 63 return 0; 64 65 return static_cast<HTMLMediaElement*>(mediaNode); 66} 67 68MediaControlElementType mediaControlElementType(Node* node) 69{ 70 ASSERT_WITH_SECURITY_IMPLICATION(node->isMediaControlElement()); 71 HTMLElement* element = toHTMLElement(node); 72 if (element->hasTagName(inputTag)) 73 return static_cast<MediaControlInputElement*>(element)->displayType(); 74 return static_cast<MediaControlDivElement*>(element)->displayType(); 75} 76 77MediaControlElement::MediaControlElement(MediaControlElementType displayType, HTMLElement* element) 78 : m_mediaController(0) 79 , m_displayType(displayType) 80 , m_element(element) 81{ 82} 83 84void MediaControlElement::hide() 85{ 86 m_element->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone); 87} 88 89void MediaControlElement::show() 90{ 91 m_element->removeInlineStyleProperty(CSSPropertyDisplay); 92} 93 94bool MediaControlElement::isShowing() const 95{ 96 const StylePropertySet* propertySet = m_element->inlineStyle(); 97 // Following the code from show() and hide() above, we only have 98 // to check for the presense of inline display. 99 return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay)); 100} 101 102void MediaControlElement::setDisplayType(MediaControlElementType displayType) 103{ 104 if (displayType == m_displayType) 105 return; 106 107 m_displayType = displayType; 108 if (RenderObject* object = m_element->renderer()) 109 object->repaint(); 110} 111 112// ---------------------------- 113 114MediaControlDivElement::MediaControlDivElement(Document* document, MediaControlElementType displayType) 115 : HTMLDivElement(divTag, document) 116 , MediaControlElement(displayType, this) 117{ 118} 119 120// ---------------------------- 121 122MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType) 123 : HTMLInputElement(inputTag, document, 0, false) 124 , MediaControlElement(displayType, this) 125{ 126} 127 128// ---------------------------- 129 130MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, MediaControlElementType displayType) 131 : MediaControlDivElement(document, displayType) 132 , m_currentValue(0) 133{ 134} 135 136void MediaControlTimeDisplayElement::setCurrentValue(double time) 137{ 138 m_currentValue = time; 139} 140 141// ---------------------------- 142 143MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType) 144 : MediaControlInputElement(document, displayType) 145{ 146} 147 148void MediaControlMuteButtonElement::defaultEventHandler(Event* event) 149{ 150 if (event->type() == eventNames().clickEvent) { 151 mediaController()->setMuted(!mediaController()->muted()); 152 event->setDefaultHandled(); 153 } 154 155 HTMLInputElement::defaultEventHandler(event); 156} 157 158void MediaControlMuteButtonElement::changedMute() 159{ 160 updateDisplayType(); 161} 162 163void MediaControlMuteButtonElement::updateDisplayType() 164{ 165 setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton); 166} 167 168// ---------------------------- 169 170MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType) 171 : MediaControlInputElement(document, displayType) 172 , m_actionOnStop(Nothing) 173 , m_seekType(Skip) 174 , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired) 175{ 176} 177 178void MediaControlSeekButtonElement::defaultEventHandler(Event* event) 179{ 180 // Set the mousedown and mouseup events as defaultHandled so they 181 // do not trigger drag start or end actions in MediaControlPanelElement. 182 if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent) 183 event->setDefaultHandled(); 184} 185 186void MediaControlSeekButtonElement::setActive(bool flag, bool pause) 187{ 188 if (flag == active()) 189 return; 190 191 if (flag) 192 startTimer(); 193 else 194 stopTimer(); 195 196 MediaControlInputElement::setActive(flag, pause); 197} 198 199void MediaControlSeekButtonElement::startTimer() 200{ 201 m_seekType = mediaController()->supportsScanning() ? Scan : Skip; 202 203 if (m_seekType == Skip) { 204 // Seeking by skipping requires the video to be paused during seeking. 205 m_actionOnStop = mediaController()->paused() ? Nothing : Play; 206 mediaController()->pause(); 207 } else { 208 // Seeking by scanning requires the video to be playing during seeking. 209 m_actionOnStop = mediaController()->paused() ? Pause : Nothing; 210 mediaController()->play(); 211 mediaController()->setPlaybackRate(nextRate()); 212 } 213 214 m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay); 215} 216 217void MediaControlSeekButtonElement::stopTimer() 218{ 219 if (m_seekType == Scan) 220 mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate()); 221 222 if (m_actionOnStop == Play) 223 mediaController()->play(); 224 else if (m_actionOnStop == Pause) 225 mediaController()->pause(); 226 227 if (m_seekTimer.isActive()) 228 m_seekTimer.stop(); 229} 230 231double MediaControlSeekButtonElement::nextRate() const 232{ 233 double rate = std::min(cScanMaximumRate, fabs(mediaController()->playbackRate() * 2)); 234 if (!isForwardButton()) 235 rate *= -1; 236 return rate; 237} 238 239void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*) 240{ 241 if (m_seekType == Skip) { 242 double skipTime = isForwardButton() ? cSkipTime : -cSkipTime; 243 mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, IGNORE_EXCEPTION); 244 } else 245 mediaController()->setPlaybackRate(nextRate()); 246} 247 248// ---------------------------- 249 250MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document) 251 : MediaControlInputElement(document, MediaVolumeSlider) 252 , m_clearMutedOnUserInteraction(false) 253{ 254} 255 256void MediaControlVolumeSliderElement::defaultEventHandler(Event* event) 257{ 258 // Left button is 0. Rejects mouse events not from left button. 259 if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button()) 260 return; 261 262 if (!attached()) 263 return; 264 265 MediaControlInputElement::defaultEventHandler(event); 266 267 if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent) 268 return; 269 270 double volume = value().toDouble(); 271 if (volume != mediaController()->volume()) 272 mediaController()->setVolume(volume, ASSERT_NO_EXCEPTION); 273 if (m_clearMutedOnUserInteraction) 274 mediaController()->setMuted(false); 275 event->setDefaultHandled(); 276} 277 278bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents() 279{ 280 if (!attached()) 281 return false; 282 283 return MediaControlInputElement::willRespondToMouseMoveEvents(); 284} 285 286bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents() 287{ 288 if (!attached()) 289 return false; 290 291 return MediaControlInputElement::willRespondToMouseClickEvents(); 292} 293 294void MediaControlVolumeSliderElement::setVolume(double volume) 295{ 296 if (value().toDouble() != volume) 297 setValue(String::number(volume)); 298} 299 300void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute) 301{ 302 m_clearMutedOnUserInteraction = clearMute; 303} 304 305} // namespace WebCore 306 307#endif // ENABLE(VIDEO) 308