ddd617047f5f5ed84c7f6ce8069a11133acd55ad
[WebKit-https.git] / WebCore / rendering / MediaControlElements.cpp
1 /*
2  * Copyright (C) 2008, 2009 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 "Event.h"
36 #include "EventNames.h"
37 #include "EventHandler.h"
38 #include "FloatConversion.h"
39 #include "Frame.h"
40 #include "HTMLNames.h"
41 #include "MouseEvent.h"
42 #include "RenderMedia.h"
43 #include "RenderSlider.h"
44 #include "RenderTheme.h"
45
46 namespace WebCore {
47
48 using namespace HTMLNames;
49
50 // FIXME: These constants may need to be tweaked to better match the seeking in the QT plugin
51 static const float cSeekRepeatDelay = 0.1f;
52 static const float cStepTime = 0.07f;
53 static const float cSeekTime = 0.2f;
54
55 MediaControlShadowRootElement::MediaControlShadowRootElement(Document* doc, HTMLMediaElement* mediaElement) 
56     : HTMLDivElement(divTag, doc)
57     , m_mediaElement(mediaElement) 
58 {
59     RefPtr<RenderStyle> rootStyle = RenderStyle::create();
60     rootStyle->inheritFrom(mediaElement->renderer()->style());
61     rootStyle->setDisplay(BLOCK);
62     rootStyle->setPosition(RelativePosition);
63     RenderMediaControlShadowRoot* renderer = new (mediaElement->renderer()->renderArena()) RenderMediaControlShadowRoot(this);
64     renderer->setStyle(rootStyle.release());
65     setRenderer(renderer);
66     setAttached();
67     setInDocument(true);
68 }
69
70 void MediaControlShadowRootElement::updateStyle()
71 {
72     if (renderer()) {
73         RenderStyle* timelineContainerStyle = m_mediaElement->renderer()->getCachedPseudoStyle(MEDIA_CONTROLS_TIMELINE_CONTAINER);
74         renderer()->setStyle(timelineContainerStyle);
75     }
76 }
77
78 // ----------------------------
79
80 MediaTextDisplayElement::MediaTextDisplayElement(Document* doc, PseudoId pseudo, HTMLMediaElement* mediaElement) 
81     : HTMLDivElement(divTag, doc)
82     , m_mediaElement(mediaElement)
83     , m_pseudoStyleId(pseudo)
84 {
85     RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
86     RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style);
87     if (renderer) {
88         setRenderer(renderer);
89         renderer->setStyle(style);
90     }
91     setAttached();
92     setInDocument(true);
93 }
94
95 void MediaTextDisplayElement::attachToParent(Element* parent)
96 {
97     parent->addChild(this);
98     if (renderer())
99         parent->renderer()->addChild(renderer());
100 }
101
102 void MediaTextDisplayElement::update()
103 {
104     if (renderer())
105         renderer()->updateFromElement();
106 }
107
108 void MediaTextDisplayElement::updateStyle()
109 {
110     if (renderer() && m_mediaElement->renderer()) {
111         RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
112         renderer()->setStyle(style);
113     }
114 }
115
116 MediaTimeDisplayElement::MediaTimeDisplayElement(Document* doc, HTMLMediaElement* element, bool currentTime)
117     : MediaTextDisplayElement(doc, currentTime ? MEDIA_CONTROLS_CURRENT_TIME_DISPLAY : MEDIA_CONTROLS_TIME_REMAINING_DISPLAY, element)
118 {
119 }
120
121 // ----------------------------
122
123 MediaControlInputElement::MediaControlInputElement(Document* doc, PseudoId pseudo, const String& type, HTMLMediaElement* mediaElement) 
124     : HTMLInputElement(inputTag, doc)
125     , m_mediaElement(mediaElement)
126     , m_pseudoStyleId(pseudo)
127 {
128     setInputType(type);
129     RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
130     RenderObject* renderer = createRenderer(m_mediaElement->renderer()->renderArena(), style);
131     if (renderer) {
132         setRenderer(renderer);
133         renderer->setStyle(style);
134     }
135     setAttached();
136     setInDocument(true);
137 }
138
139 void MediaControlInputElement::attachToParent(Element* parent)
140 {
141     parent->addChild(this);
142     parent->renderer()->addChild(renderer());
143 }
144
145 void MediaControlInputElement::update()
146 {
147     if (renderer())
148         renderer()->updateFromElement();
149 }
150
151 void MediaControlInputElement::updateStyle()
152 {
153     if (renderer() && m_mediaElement->renderer()) {
154         RenderStyle* style = m_mediaElement->renderer()->getCachedPseudoStyle(m_pseudoStyleId);
155         renderer()->setStyle(style);
156     }
157 }
158
159 bool MediaControlInputElement::hitTest(const IntPoint& absPoint)
160 {
161     if (renderer() && renderer()->style()->hasAppearance())
162         return theme()->hitTestMediaControlPart(renderer(), absPoint);
163
164     return false;
165 }
166
167 // ----------------------------
168
169 MediaControlMuteButtonElement::MediaControlMuteButtonElement(Document* doc, HTMLMediaElement* element)
170     : MediaControlInputElement(doc, MEDIA_CONTROLS_MUTE_BUTTON, "button", element)
171 {
172 }
173
174 void MediaControlMuteButtonElement::defaultEventHandler(Event* event)
175 {
176     if (event->type() == eventNames().clickEvent) {
177         m_mediaElement->setMuted(!m_mediaElement->muted());
178         event->setDefaultHandled();
179     }
180     HTMLInputElement::defaultEventHandler(event);
181 }
182
183 // ----------------------------
184
185 MediaControlPlayButtonElement::MediaControlPlayButtonElement(Document* doc, HTMLMediaElement* element)
186     : MediaControlInputElement(doc, MEDIA_CONTROLS_PLAY_BUTTON, "button", element)
187 {
188 }
189
190 void MediaControlPlayButtonElement::defaultEventHandler(Event* event)
191 {
192     if (event->type() == eventNames().clickEvent) {
193         m_mediaElement->togglePlayState();
194         event->setDefaultHandled();
195     }
196     HTMLInputElement::defaultEventHandler(event);
197 }
198
199 // ----------------------------
200
201 MediaControlSeekButtonElement::MediaControlSeekButtonElement(Document* doc, HTMLMediaElement* element, bool forward)
202     : MediaControlInputElement(doc, forward ? MEDIA_CONTROLS_SEEK_FORWARD_BUTTON : MEDIA_CONTROLS_SEEK_BACK_BUTTON, "button", element)
203     , m_forward(forward)
204     , m_seeking(false)
205     , m_capturing(false)
206     , m_seekTimer(this, &MediaControlSeekButtonElement::seekTimerFired)
207 {
208 }
209
210 void MediaControlSeekButtonElement::defaultEventHandler(Event* event)
211 {
212     if (event->type() == eventNames().mousedownEvent) {
213         if (Frame* frame = document()->frame()) {
214             m_capturing = true;
215             frame->eventHandler()->setCapturingMouseEventsNode(this);
216         }
217         m_mediaElement->pause();
218         m_seekTimer.startRepeating(cSeekRepeatDelay);
219         event->setDefaultHandled();
220     } else if (event->type() == eventNames().mouseupEvent) {
221         if (m_capturing)
222             if (Frame* frame = document()->frame()) {
223                 m_capturing = false;
224                 frame->eventHandler()->setCapturingMouseEventsNode(0);
225             }
226         ExceptionCode ec;
227         if (m_seeking || m_seekTimer.isActive()) {
228             if (!m_seeking) {
229                 float stepTime = m_forward ? cStepTime : -cStepTime;
230                 m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + stepTime, ec);
231             }
232             m_seekTimer.stop();
233             m_seeking = false;
234             event->setDefaultHandled();
235         }
236     }
237     HTMLInputElement::defaultEventHandler(event);
238 }
239
240 void MediaControlSeekButtonElement::seekTimerFired(Timer<MediaControlSeekButtonElement>*)
241 {
242     ExceptionCode ec;
243     m_seeking = true;
244     float seekTime = m_forward ? cSeekTime : -cSeekTime;
245     m_mediaElement->setCurrentTime(m_mediaElement->currentTime() + seekTime, ec);
246 }
247
248 // ----------------------------
249
250 MediaControlTimelineElement::MediaControlTimelineElement(Document* doc, HTMLMediaElement* element)
251     : MediaControlInputElement(doc, MEDIA_CONTROLS_TIMELINE, "range", element)
252
253     setAttribute(precisionAttr, "float");
254 }
255
256 void MediaControlTimelineElement::defaultEventHandler(Event* event)
257 {
258     if (event->type() == eventNames().mousedownEvent)
259         m_mediaElement->beginScrubbing();
260
261     HTMLInputElement::defaultEventHandler(event);
262
263      if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent ) {
264         return;
265     }
266
267     float time = narrowPrecisionToFloat(value().toDouble());
268     if (time != m_mediaElement->currentTime()) {
269         ExceptionCode ec;
270         m_mediaElement->setCurrentTime(time, ec);
271     }
272
273     RenderSlider* slider = static_cast<RenderSlider*>(renderer());
274     if (slider && slider->inDragMode())
275         static_cast<RenderMedia*>(m_mediaElement->renderer())->updateTimeDisplay();
276
277     if (event->type() == eventNames().mouseupEvent)
278         m_mediaElement->endScrubbing();
279 }
280
281 void MediaControlTimelineElement::update(bool updateDuration) 
282 {
283     if (updateDuration) {
284         float dur = m_mediaElement->duration();
285         setAttribute(maxAttr, String::number(isfinite(dur) ? dur : 0));
286     }
287     setValue(String::number(m_mediaElement->currentTime()));
288 }
289
290 // ----------------------------
291
292 MediaControlFullscreenButtonElement::MediaControlFullscreenButtonElement(Document* doc, HTMLMediaElement* element)
293     : MediaControlInputElement(doc, MEDIA_CONTROLS_FULLSCREEN_BUTTON, "button", element)
294 {
295 }
296
297 void MediaControlFullscreenButtonElement::defaultEventHandler(Event* event)
298 {
299     if (event->type() == eventNames().clickEvent) {
300         event->setDefaultHandled();
301     }
302     HTMLInputElement::defaultEventHandler(event);
303 }
304
305 // ----------------------------
306
307 } //namespace WebCore
308 #endif // enable(video)