cb8a3a845e8f1b96e4682b34dc94492b4f332ac3
[WebKit-https.git] / Source / WebCore / html / shadow / MediaControlRootElementChromium.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 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  * 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  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26
27 #include "config.h"
28
29 #if ENABLE(VIDEO)
30 #include "MediaControlRootElementChromium.h"
31
32 #include "HTMLDivElement.h"
33 #include "HTMLMediaElement.h"
34 #include "HTMLNames.h"
35 #include "MediaControlElements.h"
36 #include "MouseEvent.h"
37 #include "Page.h"
38 #include "RenderTheme.h"
39 #include "Text.h"
40
41 #if ENABLE(VIDEO_TRACK)
42 #include "TextTrackCue.h"
43 #endif
44
45 using namespace std;
46
47 namespace WebCore {
48
49 MediaControlChromiumEnclosureElement::MediaControlChromiumEnclosureElement(Document* document)
50     : HTMLDivElement(HTMLNames::divTag, document->document())
51     , m_mediaController(0)
52 {
53 }
54
55 PassRefPtr<MediaControlChromiumEnclosureElement> MediaControlChromiumEnclosureElement::create(Document* document)
56 {
57     return adoptRef(new MediaControlChromiumEnclosureElement(document));
58 }
59
60 const AtomicString& MediaControlChromiumEnclosureElement::shadowPseudoId() const
61 {
62     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-enclosure"));
63     return id;
64 }
65
66 MediaControlRootElementChromium::MediaControlRootElementChromium(Document* document)
67     : MediaControls(document)
68     , m_mediaController(0)
69     , m_playButton(0)
70     , m_currentTimeDisplay(0)
71     , m_timeline(0)
72     , m_timelineContainer(0)
73     , m_panelMuteButton(0)
74     , m_volumeSlider(0)
75     , m_volumeSliderContainer(0)
76 #if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
77     , m_fullscreenButton(0)
78 #endif
79     , m_panel(0)
80     , m_enclosure(0)
81 #if ENABLE(VIDEO_TRACK)
82     , m_textDisplayContainer(0)
83 #endif
84     , m_opaque(true)
85     , m_isMouseOverControls(false)
86 {
87 }
88
89 PassRefPtr<MediaControls> MediaControls::create(Document* document)
90 {
91     return MediaControlRootElementChromium::create(document);
92 }
93
94 PassRefPtr<MediaControlRootElementChromium> MediaControlRootElementChromium::create(Document* document)
95 {
96     if (!document->page())
97         return 0;
98
99     RefPtr<MediaControlRootElementChromium> controls = adoptRef(new MediaControlRootElementChromium(document));
100
101     // Create an enclosing element for the panel so we can visually offset the controls correctly.
102     RefPtr<MediaControlChromiumEnclosureElement> enclosure = MediaControlChromiumEnclosureElement::create(document);
103
104     RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document);
105
106     ExceptionCode ec;
107
108     RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(document);
109     controls->m_playButton = playButton.get();
110     panel->appendChild(playButton.release(), ec, true);
111     if (ec)
112         return 0;
113
114     RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(document);
115
116     RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, controls.get());
117     controls->m_timeline = timeline.get();
118     timelineContainer->appendChild(timeline.release(), ec, true);
119     if (ec)
120         return 0;
121
122     RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document);
123     controls->m_currentTimeDisplay = currentTimeDisplay.get();
124     timelineContainer->appendChild(currentTimeDisplay.release(), ec, true);
125     if (ec)
126         return 0;
127
128     controls->m_timelineContainer = timelineContainer.get();
129     panel->appendChild(timelineContainer.release(), ec, true);
130     if (ec)
131         return 0;
132
133     RefPtr<HTMLDivElement> panelVolumeControlContainer = HTMLDivElement::create(document);
134
135     RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document);
136
137     RefPtr<MediaControlVolumeSliderElement> slider = MediaControlVolumeSliderElement::create(document);
138     controls->m_volumeSlider = slider.get();
139     volumeSliderContainer->appendChild(slider.release(), ec, true);
140     if (ec)
141         return 0;
142
143     controls->m_volumeSliderContainer = volumeSliderContainer.get();
144     panelVolumeControlContainer->appendChild(volumeSliderContainer.release(), ec, true);
145     if (ec)
146         return 0;
147
148     RefPtr<MediaControlPanelMuteButtonElement> panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.get());
149     controls->m_panelMuteButton = panelMuteButton.get();
150     panelVolumeControlContainer->appendChild(panelMuteButton.release(), ec, true);
151     if (ec)
152         return 0;
153
154     panel->appendChild(panelVolumeControlContainer, ec, true);
155     if (ec)
156         return 0;
157
158 #if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
159     RefPtr<MediaControlFullscreenButtonElement> fullscreenButton = MediaControlFullscreenButtonElement::create(document, controls.get());
160     controls->m_fullscreenButton = fullscreenButton.get();
161     panel->appendChild(fullscreenButton.release(), ec, true);
162     if (ec)
163         return 0;
164 #endif
165
166     controls->m_panel = panel.get();
167     enclosure->appendChild(panel.release(), ec, true);
168     if (ec)
169         return 0;
170
171     controls->m_enclosure = enclosure.get();
172     controls->appendChild(enclosure.release(), ec, true);
173     if (ec)
174         return 0;
175
176     return controls.release();
177 }
178
179 void MediaControlRootElementChromium::setMediaController(MediaControllerInterface* controller)
180 {
181     if (m_mediaController == controller)
182         return;
183     m_mediaController = controller;
184
185     if (m_playButton)
186         m_playButton->setMediaController(controller);
187     if (m_currentTimeDisplay)
188         m_currentTimeDisplay->setMediaController(controller);
189     if (m_timeline)
190         m_timeline->setMediaController(controller);
191     if (m_timelineContainer)
192         m_timelineContainer->setMediaController(controller);
193     if (m_panelMuteButton)
194         m_panelMuteButton->setMediaController(controller);
195     if (m_volumeSlider)
196         m_volumeSlider->setMediaController(controller);
197     if (m_volumeSliderContainer)
198         m_volumeSliderContainer->setMediaController(controller);
199 #if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
200     if (m_fullscreenButton)
201         m_fullscreenButton->setMediaController(controller);
202 #endif
203     if (m_panel)
204         m_panel->setMediaController(controller);
205     if (m_enclosure)
206         m_enclosure->setMediaController(controller);
207 #if ENABLE(VIDEO_TRACK)
208     if (m_textDisplayContainer)
209         m_textDisplayContainer->setMediaController(controller);
210 #endif
211     reset();
212 }
213
214 void MediaControlRootElementChromium::show()
215 {
216     m_panel->setIsDisplayed(true);
217     m_panel->show();
218 }
219
220 void MediaControlRootElementChromium::hide()
221 {
222     m_panel->setIsDisplayed(false);
223     m_panel->hide();
224     m_volumeSliderContainer->hide();
225 }
226
227 void MediaControlRootElementChromium::makeOpaque()
228 {
229     m_panel->makeOpaque();
230 }
231
232 void MediaControlRootElementChromium::makeTransparent()
233 {
234     m_panel->makeTransparent();
235     m_volumeSliderContainer->hide();
236 }
237
238 void MediaControlRootElementChromium::reset()
239 {
240     Page* page = document()->page();
241     if (!page)
242         return;
243
244     updateStatusDisplay();
245
246     float duration = m_mediaController->duration();
247     m_timeline->setDuration(duration);
248     m_timelineContainer->show();
249     m_timeline->setPosition(m_mediaController->currentTime());
250     updateTimeDisplay();
251
252     m_panelMuteButton->show();
253
254     if (m_volumeSlider)
255         m_volumeSlider->setVolume(m_mediaController->volume());
256
257 #if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
258     m_fullscreenButton->show();
259 #endif
260     makeOpaque();
261 }
262
263 void MediaControlRootElementChromium::playbackStarted()
264 {
265     m_playButton->updateDisplayType();
266     m_timeline->setPosition(m_mediaController->currentTime());
267     updateTimeDisplay();
268 }
269
270 void MediaControlRootElementChromium::playbackProgressed()
271 {
272     m_timeline->setPosition(m_mediaController->currentTime());
273     updateTimeDisplay();
274
275     if (!m_isMouseOverControls && m_mediaController->hasVideo())
276         makeTransparent();
277 }
278
279 void MediaControlRootElementChromium::playbackStopped()
280 {
281     m_playButton->updateDisplayType();
282     m_timeline->setPosition(m_mediaController->currentTime());
283     updateTimeDisplay();
284     makeOpaque();
285 }
286
287 void MediaControlRootElementChromium::updateTimeDisplay()
288 {
289     float now = m_mediaController->currentTime();
290     float duration = m_mediaController->duration();
291
292     Page* page = document()->page();
293     if (!page)
294         return;
295
296     // Allow the theme to format the time.
297     ExceptionCode ec;
298     m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), ec);
299     m_currentTimeDisplay->setCurrentValue(now);
300 }
301
302 void MediaControlRootElementChromium::reportedError()
303 {
304     Page* page = document()->page();
305     if (!page)
306         return;
307
308     m_timelineContainer->hide();
309     m_panelMuteButton->hide();
310     m_volumeSliderContainer->hide();
311 #if ENABLE(FULLSCREEN_MEDIA_CONTROLS)
312     m_fullscreenButton->hide();
313 #endif
314 }
315
316 void MediaControlRootElementChromium::updateStatusDisplay()
317 {
318 }
319
320 bool MediaControlRootElementChromium::shouldHideControls()
321 {
322     return !m_panel->hovered();
323 }
324
325 void MediaControlRootElementChromium::loadedMetadata()
326 {
327     reset();
328 }
329
330 bool MediaControlRootElementChromium::containsRelatedTarget(Event* event)
331 {
332     if (!event->isMouseEvent())
333         return false;
334     EventTarget* relatedTarget = static_cast<MouseEvent*>(event)->relatedTarget();
335     if (!relatedTarget)
336         return false;
337     return contains(relatedTarget->toNode());
338 }
339
340 void MediaControlRootElementChromium::defaultEventHandler(Event* event)
341 {
342     MediaControls::defaultEventHandler(event);
343
344     if (event->type() == eventNames().mouseoverEvent) {
345         if (!containsRelatedTarget(event)) {
346             m_isMouseOverControls = true;
347             if (!m_mediaController->canPlay())
348                 makeOpaque();
349         }
350     } else if (event->type() == eventNames().mouseoutEvent) {
351         if (!containsRelatedTarget(event))
352             m_isMouseOverControls = false;
353     }
354 }
355
356 void MediaControlRootElementChromium::changedClosedCaptionsVisibility()
357 {
358 }
359
360 void MediaControlRootElementChromium::changedMute()
361 {
362     m_panelMuteButton->changedMute();
363 }
364
365 void MediaControlRootElementChromium::changedVolume()
366 {
367     m_volumeSlider->setVolume(m_mediaController->volume());
368 }
369
370 void MediaControlRootElementChromium::enteredFullscreen()
371 {
372 }
373
374 void MediaControlRootElementChromium::exitedFullscreen()
375 {
376 }
377
378 void MediaControlRootElementChromium::showVolumeSlider()
379 {
380     if (!m_mediaController->hasAudio())
381         return;
382
383     m_volumeSliderContainer->show();
384 }
385
386 #if ENABLE(VIDEO_TRACK)
387 void MediaControlRootElementChromium::createTextTrackDisplay()
388 {
389     if (m_textDisplayContainer)
390         return;
391
392     RefPtr<MediaControlTextTrackContainerElement> textDisplayContainer = MediaControlTextTrackContainerElement::create(document());
393     m_textDisplayContainer = textDisplayContainer.get();
394
395     // Insert it before the first controller element so it always displays behind the controls.
396     insertBefore(textDisplayContainer.release(), m_enclosure, ASSERT_NO_EXCEPTION, true);
397 }
398
399 void MediaControlRootElementChromium::showTextTrackDisplay()
400 {
401     if (!m_textDisplayContainer)
402         createTextTrackDisplay();
403     m_textDisplayContainer->show();
404 }
405
406 void MediaControlRootElementChromium::hideTextTrackDisplay()
407 {
408     if (!m_textDisplayContainer)
409         createTextTrackDisplay();
410     m_textDisplayContainer->hide();
411 }
412
413 void MediaControlRootElementChromium::updateTextTrackDisplay()
414 {
415     if (!m_textDisplayContainer)
416         createTextTrackDisplay();
417
418     m_textDisplayContainer->updateDisplay();
419 }
420 #endif
421
422 const AtomicString& MediaControlRootElementChromium::shadowPseudoId() const
423 {
424     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls"));
425     return id;
426 }
427
428 void MediaControlRootElementChromium::bufferingProgressed()
429 {
430     // We only need to update buffering progress when paused, during normal
431     // playback playbackProgressed() will take care of it.
432     if (m_mediaController->paused())
433         m_timeline->setPosition(m_mediaController->currentTime());
434 }
435
436 }
437
438 #endif