Source/WebCore: Source/WebCore: Mac: Media Controls always hide time display elements
[WebKit-https.git] / Source / WebCore / html / shadow / MediaControlElementTypes.cpp
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 "FloatConversion.h"
38 #include "HTMLNames.h"
39 #include "MouseEvent.h"
40 #include "RenderMedia.h"
41 #include "RenderMediaControlElements.h"
42 #include "StylePropertySet.h"
43
44 namespace WebCore {
45
46 using namespace HTMLNames;
47
48 class Event;
49
50 // FIXME: These constants may need to be tweaked to better match the seeking in the QuickTime plug-in.
51 static const float cSkipRepeatDelay = 0.1f;
52 static const float cSkipTime = 0.2f;
53 static const float cScanRepeatDelay = 1.5f;
54 static const float cScanMaximumRate = 8;
55
56 HTMLMediaElement* toParentMediaElement(Node* node)
57 {
58     if (!node)
59         return 0;
60     Node* mediaNode = node->shadowHost();
61     if (!mediaNode)
62         mediaNode = node;
63     if (!mediaNode || !mediaNode->isElementNode() || !toElement(mediaNode)->isMediaElement())
64         return 0;
65
66     return static_cast<HTMLMediaElement*>(mediaNode);
67 }
68
69 MediaControlElementType mediaControlElementType(Node* node)
70 {
71     ASSERT_WITH_SECURITY_IMPLICATION(node->isMediaControlElement());
72     HTMLElement* element = toHTMLElement(node);
73     if (element->hasTagName(inputTag))
74         return static_cast<MediaControlInputElement*>(element)->displayType();
75     return static_cast<MediaControlDivElement*>(element)->displayType();
76 }
77
78 #if ENABLE(VIDEO_TRACK)
79 const AtomicString& trackIndexAttributeName()
80 {
81     DEFINE_STATIC_LOCAL(AtomicString, name, ("x-webkit-track-index", AtomicString::ConstructFromLiteral));
82     return name;
83 }
84
85 int trackListIndexForElement(Element* element)
86 {
87     const AtomicString trackIndexAttributeValue = element->getAttribute(trackIndexAttributeName());
88     if (trackIndexAttributeValue.isNull() || trackIndexAttributeValue.isEmpty())
89         return HTMLMediaElement::textTracksIndexNotFound();
90     bool ok;
91     int trackIndex = trackIndexAttributeValue.toInt(&ok);
92     if (!ok)
93         return HTMLMediaElement::textTracksIndexNotFound();
94     return trackIndex;
95 }
96 #endif
97
98 MediaControlElement::MediaControlElement(MediaControlElementType displayType, HTMLElement* element)
99     : m_mediaController(0)
100     , m_displayType(displayType)
101     , m_element(element)
102 {
103 }
104
105 void MediaControlElement::hide()
106 {
107     m_element->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
108 }
109
110 void MediaControlElement::show()
111 {
112     m_element->removeInlineStyleProperty(CSSPropertyDisplay);
113 }
114
115 bool MediaControlElement::isShowing() const
116 {
117     const StylePropertySet* propertySet = m_element->inlineStyle();
118     // Following the code from show() and hide() above, we only have
119     // to check for the presense of inline display.
120     return (!propertySet || !propertySet->getPropertyCSSValue(CSSPropertyDisplay));
121 }
122
123 void MediaControlElement::setDisplayType(MediaControlElementType displayType)
124 {
125     if (displayType == m_displayType)
126         return;
127
128     m_displayType = displayType;
129     if (RenderObject* object = m_element->renderer())
130         object->repaint();
131 }
132
133 // ----------------------------
134
135 MediaControlDivElement::MediaControlDivElement(Document* document, MediaControlElementType displayType)
136     : HTMLDivElement(divTag, document)
137     , MediaControlElement(displayType, this)
138 {
139 }
140
141 // ----------------------------
142
143 MediaControlInputElement::MediaControlInputElement(Document* document, MediaControlElementType displayType)
144     : HTMLInputElement(inputTag, document, 0, false)
145     , MediaControlElement(displayType, this)
146 {
147 }
148
149 // ----------------------------
150
151 MediaControlTimeDisplayElement::MediaControlTimeDisplayElement(Document* document, MediaControlElementType displayType)
152     : MediaControlDivElement(document, displayType)
153     , m_currentValue(0)
154 {
155 }
156
157 void MediaControlTimeDisplayElement::setCurrentValue(float time)
158 {
159     m_currentValue = time;
160 }
161
162 // ----------------------------
163
164 MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* document, MediaControlElementType displayType)
165     : MediaControlInputElement(document, displayType)
166 {
167 }
168
169 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
170 {
171     if (event->type() == eventNames().clickEvent) {
172         mediaController()->setMuted(!mediaController()->muted());
173         event->setDefaultHandled();
174     }
175
176     HTMLInputElement::defaultEventHandler(event);
177 }
178
179 void MediaControlMuteButtonElement::changedMute()
180 {
181     updateDisplayType();
182 }
183
184 void MediaControlMuteButtonElement::updateDisplayType()
185 {
186     setDisplayType(mediaController()->muted() ? MediaUnMuteButton : MediaMuteButton);
187 }
188
189 // ----------------------------
190
191 MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* document, MediaControlElementType displayType)
192     : MediaControlInputElement(document, displayType)
193     , m_actionOnStop(Nothing)
194     , m_seekType(Skip)
195     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
196 {
197 }
198
199 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
200 {
201     // Set the mousedown and mouseup events as defaultHandled so they
202     // do not trigger drag start or end actions in MediaControlPanelElement.
203     if (event->type() == eventNames().mousedownEvent || event->type() == eventNames().mouseupEvent)
204         event->setDefaultHandled();
205 }
206
207 void MediaControlSeekButtonElement::setActive(bool flag, bool pause)
208 {
209     if (flag == active())
210         return;
211
212     if (flag)
213         startTimer();
214     else
215         stopTimer();
216
217     MediaControlInputElement::setActive(flag, pause);
218 }
219
220 void MediaControlSeekButtonElement::startTimer()
221 {
222     m_seekType = mediaController()->supportsScanning() ? Scan : Skip;
223
224     if (m_seekType == Skip) {
225         // Seeking by skipping requires the video to be paused during seeking.
226         m_actionOnStop = mediaController()->paused() ? Nothing : Play;
227         mediaController()->pause();
228     } else {
229         // Seeking by scanning requires the video to be playing during seeking.
230         m_actionOnStop = mediaController()->paused() ? Pause : Nothing;
231         mediaController()->play();
232         mediaController()->setPlaybackRate(nextRate());
233     }
234
235     m_seekTimer.start(0, m_seekType == Skip ? cSkipRepeatDelay : cScanRepeatDelay);
236 }
237
238 void MediaControlSeekButtonElement::stopTimer()
239 {
240     if (m_seekType == Scan)
241         mediaController()->setPlaybackRate(mediaController()->defaultPlaybackRate());
242
243     if (m_actionOnStop == Play)
244         mediaController()->play();
245     else if (m_actionOnStop == Pause)
246         mediaController()->pause();
247
248     if (m_seekTimer.isActive())
249         m_seekTimer.stop();
250 }
251
252 float MediaControlSeekButtonElement::nextRate() const
253 {
254     float rate = std::min(cScanMaximumRate, fabsf(mediaController()->playbackRate() * 2));
255     if (!isForwardButton())
256         rate *= -1;
257     return rate;
258 }
259
260 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
261 {
262     if (m_seekType == Skip) {
263         float skipTime = isForwardButton() ? cSkipTime : -cSkipTime;
264         mediaController()->setCurrentTime(mediaController()->currentTime() + skipTime, IGNORE_EXCEPTION);
265     } else
266         mediaController()->setPlaybackRate(nextRate());
267 }
268
269 // ----------------------------
270
271 MediaControlVolumeSliderElement::MediaControlVolumeSliderElement(Document* document)
272     : MediaControlInputElement(document, MediaVolumeSlider)
273     , m_clearMutedOnUserInteraction(false)
274 {
275 }
276
277 void MediaControlVolumeSliderElement::defaultEventHandler(Event* event)
278 {
279     // Left button is 0. Rejects mouse events not from left button.
280     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
281         return;
282
283     if (!attached())
284         return;
285
286     MediaControlInputElement::defaultEventHandler(event);
287
288     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
289         return;
290
291     float volume = narrowPrecisionToFloat(value().toDouble());
292     if (volume != mediaController()->volume())
293         mediaController()->setVolume(volume, ASSERT_NO_EXCEPTION);
294     if (m_clearMutedOnUserInteraction)
295         mediaController()->setMuted(false);
296 }
297
298 bool MediaControlVolumeSliderElement::willRespondToMouseMoveEvents()
299 {
300     if (!attached())
301         return false;
302
303     return MediaControlInputElement::willRespondToMouseMoveEvents();
304 }
305
306 bool MediaControlVolumeSliderElement::willRespondToMouseClickEvents()
307 {
308     if (!attached())
309         return false;
310
311     return MediaControlInputElement::willRespondToMouseClickEvents();
312 }
313
314 void MediaControlVolumeSliderElement::setVolume(float volume)
315 {
316     if (value().toFloat() != volume)
317         setValue(String::number(volume));
318 }
319
320 void MediaControlVolumeSliderElement::setClearMutedOnUserInteraction(bool clearMute)
321 {
322     m_clearMutedOnUserInteraction = clearMute;
323 }
324
325 } // namespace WebCore
326
327 #endif // ENABLE(VIDEO)