Add WebSocketProvider stub
[WebKit-https.git] / Source / WebCore / html / shadow / MediaControlsApple.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2011, 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  * 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 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 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 "MediaControlsApple.h"
31
32 #include "CSSValueKeywords.h"
33 #include "ExceptionCodePlaceholder.h"
34 #include "HTMLNames.h"
35 #include "Page.h"
36 #include "WheelEvent.h"
37
38 namespace WebCore {
39
40 MediaControlsApple::MediaControlsApple(Document& document)
41     : MediaControls(document)
42     , m_rewindButton(0)
43     , m_returnToRealTimeButton(0)
44     , m_statusDisplay(0)
45     , m_timeRemainingDisplay(0)
46     , m_timelineContainer(0)
47     , m_seekBackButton(0)
48     , m_seekForwardButton(0)
49     , m_closedCaptionsTrackList(0)
50     , m_closedCaptionsContainer(0)
51     , m_volumeSliderMuteButton(0)
52     , m_volumeSliderContainer(0)
53     , m_fullScreenMinVolumeButton(0)
54     , m_fullScreenVolumeSlider(0)
55     , m_fullScreenMaxVolumeButton(0)
56 {
57 }
58
59 RefPtr<MediaControls> MediaControls::tryCreate(Document& document)
60 {
61     return MediaControlsApple::tryCreateControls(document);
62 }
63
64 RefPtr<MediaControlsApple> MediaControlsApple::tryCreateControls(Document& document)
65 {
66     if (!document.page())
67         return nullptr;
68
69     auto controls = adoptRef(*new MediaControlsApple(document));
70
71     auto panel = MediaControlPanelElement::create(document);
72
73     ExceptionCode ec;
74
75     auto rewindButton = MediaControlRewindButtonElement::create(document);
76     controls->m_rewindButton = rewindButton.ptr();
77     panel->appendChild(rewindButton, ec);
78     if (ec)
79         return nullptr;
80
81     auto playButton = MediaControlPlayButtonElement::create(document);
82     controls->m_playButton = playButton.ptr();
83     panel->appendChild(playButton, ec);
84     if (ec)
85         return nullptr;
86
87     auto returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(document);
88     controls->m_returnToRealTimeButton = returnToRealtimeButton.ptr();
89     panel->appendChild(returnToRealtimeButton, ec);
90     if (ec)
91         return nullptr;
92
93     if (document.page()->theme().usesMediaControlStatusDisplay()) {
94         auto statusDisplay = MediaControlStatusDisplayElement::create(document);
95         controls->m_statusDisplay = statusDisplay.ptr();
96         panel->appendChild(statusDisplay, ec);
97         if (ec)
98             return nullptr;
99     }
100
101     auto timelineContainer = MediaControlTimelineContainerElement::create(document);
102
103     auto currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document);
104     controls->m_currentTimeDisplay = currentTimeDisplay.ptr();
105     timelineContainer->appendChild(currentTimeDisplay, ec);
106     if (ec)
107         return nullptr;
108
109     auto timeline = MediaControlTimelineElement::create(document, controls.ptr());
110     controls->m_timeline = timeline.ptr();
111     timelineContainer->appendChild(timeline, ec);
112     if (ec)
113         return nullptr;
114
115     auto timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document);
116     controls->m_timeRemainingDisplay = timeRemainingDisplay.ptr();
117     timelineContainer->appendChild(timeRemainingDisplay, ec);
118     if (ec)
119         return nullptr;
120
121     controls->m_timelineContainer = timelineContainer.ptr();
122     panel->appendChild(timelineContainer, ec);
123     if (ec)
124         return nullptr;
125
126     // FIXME: Only create when needed <http://webkit.org/b/57163>
127     auto seekBackButton = MediaControlSeekBackButtonElement::create(document);
128     controls->m_seekBackButton = seekBackButton.ptr();
129     panel->appendChild(seekBackButton, ec);
130     if (ec)
131         return nullptr;
132
133     // FIXME: Only create when needed <http://webkit.org/b/57163>
134     auto seekForwardButton = MediaControlSeekForwardButtonElement::create(document);
135     controls->m_seekForwardButton = seekForwardButton.ptr();
136     panel->appendChild(seekForwardButton, ec);
137     if (ec)
138         return nullptr;
139
140     if (document.page()->theme().supportsClosedCaptioning()) {
141         auto closedCaptionsContainer = MediaControlClosedCaptionsContainerElement::create(document);
142
143         auto closedCaptionsTrackList = MediaControlClosedCaptionsTrackListElement::create(document, controls.ptr());
144         controls->m_closedCaptionsTrackList = closedCaptionsTrackList.ptr();
145         closedCaptionsContainer->appendChild(closedCaptionsTrackList, ec);
146         if (ec)
147             return nullptr;
148
149         auto toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.ptr());
150         controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.ptr();
151         panel->appendChild(toggleClosedCaptionsButton, ec);
152         if (ec)
153             return nullptr;
154
155         controls->m_closedCaptionsContainer = closedCaptionsContainer.ptr();
156         controls->appendChild(closedCaptionsContainer, ec);
157         if (ec)
158             return nullptr;
159     }
160
161     // FIXME: Only create when needed <http://webkit.org/b/57163>
162     auto fullScreenButton = MediaControlFullscreenButtonElement::create(document);
163     controls->m_fullScreenButton = fullScreenButton.ptr();
164     panel->appendChild(fullScreenButton, ec);
165
166     // The mute button and the slider element should be in the same div.
167     auto panelVolumeControlContainer = HTMLDivElement::create(document);
168
169     if (document.page()->theme().usesMediaControlVolumeSlider()) {
170         auto volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document);
171
172         auto slider = MediaControlPanelVolumeSliderElement::create(document);
173         controls->m_volumeSlider = slider.ptr();
174         volumeSliderContainer->appendChild(slider, ec);
175         if (ec)
176             return nullptr;
177
178         // This is a duplicate mute button, which is visible in some ports at the bottom of the volume bar.
179         // It's important only when the volume bar is displayed below the controls.
180         auto volumeSliderMuteButton = MediaControlVolumeSliderMuteButtonElement::create(document);
181         controls->m_volumeSliderMuteButton = volumeSliderMuteButton.ptr();
182         volumeSliderContainer->appendChild(volumeSliderMuteButton, ec);
183
184         if (ec)
185             return nullptr;
186
187         controls->m_volumeSliderContainer = volumeSliderContainer.ptr();
188         panelVolumeControlContainer->appendChild(volumeSliderContainer, ec);
189         if (ec)
190             return nullptr;
191     }
192
193     auto panelMuteButton = MediaControlPanelMuteButtonElement::create(document, controls.ptr());
194     controls->m_panelMuteButton = panelMuteButton.ptr();
195     panelVolumeControlContainer->appendChild(panelMuteButton, ec);
196     if (ec)
197         return nullptr;
198
199     panel->appendChild(panelVolumeControlContainer, ec);
200     if (ec)
201         return nullptr;
202
203     // FIXME: Only create when needed <http://webkit.org/b/57163>
204     auto fullScreenMinVolumeButton = MediaControlFullscreenVolumeMinButtonElement::create(document);
205     controls->m_fullScreenMinVolumeButton = fullScreenMinVolumeButton.ptr();
206     panel->appendChild(fullScreenMinVolumeButton, ec);
207     if (ec)
208         return nullptr;
209
210     auto fullScreenVolumeSlider = MediaControlFullscreenVolumeSliderElement::create(document);
211     controls->m_fullScreenVolumeSlider = fullScreenVolumeSlider.ptr();
212     panel->appendChild(fullScreenVolumeSlider, ec);
213     if (ec)
214         return nullptr;
215
216     auto fullScreenMaxVolumeButton = MediaControlFullscreenVolumeMaxButtonElement::create(document);
217     controls->m_fullScreenMaxVolumeButton = fullScreenMaxVolumeButton.ptr();
218     panel->appendChild(fullScreenMaxVolumeButton, ec);
219     if (ec)
220         return nullptr;
221
222     controls->m_panel = panel.ptr();
223     controls->appendChild(panel, ec);
224     if (ec)
225         return nullptr;
226
227     return WTFMove(controls);
228 }
229
230 void MediaControlsApple::setMediaController(MediaControllerInterface* controller)
231 {
232     if (m_mediaController == controller)
233         return;
234
235     MediaControls::setMediaController(controller);
236
237     if (m_rewindButton)
238         m_rewindButton->setMediaController(controller);
239     if (m_returnToRealTimeButton)
240         m_returnToRealTimeButton->setMediaController(controller);
241     if (m_statusDisplay)
242         m_statusDisplay->setMediaController(controller);
243     if (m_timeRemainingDisplay)
244         m_timeRemainingDisplay->setMediaController(controller);
245     if (m_timelineContainer)
246         m_timelineContainer->setMediaController(controller);
247     if (m_seekBackButton)
248         m_seekBackButton->setMediaController(controller);
249     if (m_seekForwardButton)
250         m_seekForwardButton->setMediaController(controller);
251     if (m_volumeSliderMuteButton)
252         m_volumeSliderMuteButton->setMediaController(controller);
253     if (m_volumeSliderContainer)
254         m_volumeSliderContainer->setMediaController(controller);
255     if (m_fullScreenMinVolumeButton)
256         m_fullScreenMinVolumeButton->setMediaController(controller);
257     if (m_fullScreenVolumeSlider)
258         m_fullScreenVolumeSlider->setMediaController(controller);
259     if (m_fullScreenMaxVolumeButton)
260         m_fullScreenMaxVolumeButton->setMediaController(controller);
261     if (m_closedCaptionsTrackList)
262         m_closedCaptionsTrackList->setMediaController(controller);
263     if (m_closedCaptionsContainer)
264         m_closedCaptionsContainer->setMediaController(controller);
265 }
266
267 void MediaControlsApple::defaultEventHandler(Event* event)
268 {
269     if (event->type() == eventNames().clickEvent) {
270         if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing()) {
271             hideClosedCaptionTrackList();
272             event->setDefaultHandled();
273         }
274     }
275
276     MediaControls::defaultEventHandler(event);
277 }
278
279 void MediaControlsApple::hide()
280 {
281     MediaControls::hide();
282     m_volumeSliderContainer->hide();
283     if (m_closedCaptionsContainer)
284         hideClosedCaptionTrackList();
285 }
286
287 void MediaControlsApple::makeTransparent()
288 {
289     MediaControls::makeTransparent();
290     m_volumeSliderContainer->hide();
291     if (m_closedCaptionsContainer)
292         hideClosedCaptionTrackList();
293 }
294
295 void MediaControlsApple::changedClosedCaptionsVisibility()
296 {
297     MediaControls::changedClosedCaptionsVisibility();
298     if (m_closedCaptionsContainer && m_closedCaptionsContainer->isShowing())
299         hideClosedCaptionTrackList();
300
301 }
302
303 void MediaControlsApple::reset()
304 {
305     Page* page = document().page();
306     if (!page)
307         return;
308
309     updateStatusDisplay();
310
311     if (m_mediaController->supportsFullscreen(HTMLMediaElementEnums::VideoFullscreenModeStandard))
312         m_fullScreenButton->show();
313     else
314         m_fullScreenButton->hide();
315
316     double duration = m_mediaController->duration();
317     if (std::isfinite(duration) || page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
318         m_timeline->setDuration(duration);
319         m_timelineContainer->show();
320         m_timeline->setPosition(m_mediaController->currentTime());
321         updateCurrentTimeDisplay();
322     } else
323         m_timelineContainer->hide();
324
325     if (m_mediaController->hasAudio() || page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
326         m_panelMuteButton->show();
327     else
328         m_panelMuteButton->hide();
329
330     if (m_volumeSlider)
331         setSliderVolume();
332
333     if (m_toggleClosedCaptionsButton) {
334         if (m_mediaController->hasClosedCaptions())
335             m_toggleClosedCaptionsButton->show();
336         else
337             m_toggleClosedCaptionsButton->hide();
338     }
339
340     if (m_playButton)
341         m_playButton->updateDisplayType();
342
343 #if ENABLE(FULLSCREEN_API)
344     if (m_fullScreenVolumeSlider)
345         setFullscreenSliderVolume();
346
347     if (m_isFullscreen) {
348         if (m_mediaController->isLiveStream()) {
349             m_seekBackButton->hide();
350             m_seekForwardButton->hide();
351             m_rewindButton->show();
352             m_returnToRealTimeButton->show();
353         } else {
354             m_seekBackButton->show();
355             m_seekForwardButton->show();
356             m_rewindButton->hide();
357             m_returnToRealTimeButton->hide();
358         }
359     } else
360 #endif
361     if (!m_mediaController->isLiveStream()) {
362         m_returnToRealTimeButton->hide();
363         m_rewindButton->show();
364     } else {
365         m_returnToRealTimeButton->show();
366         m_rewindButton->hide();
367     }
368
369     makeOpaque();
370 }
371
372 void MediaControlsApple::updateCurrentTimeDisplay()
373 {
374     double now = m_mediaController->currentTime();
375     double duration = m_mediaController->duration();
376
377     Page* page = document().page();
378     if (!page)
379         return;
380
381     // Allow the theme to format the time.
382     m_currentTimeDisplay->setInnerText(page->theme().formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION);
383     m_currentTimeDisplay->setCurrentValue(now);
384     m_timeRemainingDisplay->setInnerText(page->theme().formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION);
385     m_timeRemainingDisplay->setCurrentValue(now - duration);
386 }
387
388 void MediaControlsApple::reportedError()
389 {
390     Page* page = document().page();
391     if (!page)
392         return;
393
394     if (!page->theme().hasOwnDisabledStateHandlingFor(MediaSliderPart))
395         m_timelineContainer->hide();
396
397     if (!page->theme().hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
398         m_panelMuteButton->hide();
399
400     m_fullScreenButton->hide();
401
402     if (m_volumeSliderContainer)
403         m_volumeSliderContainer->hide();
404     if (m_toggleClosedCaptionsButton && !page->theme().hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
405         m_toggleClosedCaptionsButton->hide();
406     if (m_closedCaptionsContainer)
407         hideClosedCaptionTrackList();
408 }
409
410 void MediaControlsApple::updateStatusDisplay()
411 {
412     if (m_statusDisplay)
413         m_statusDisplay->update();
414 }
415
416 void MediaControlsApple::loadedMetadata()
417 {
418     if (m_statusDisplay && !m_mediaController->isLiveStream())
419         m_statusDisplay->hide();
420
421     MediaControls::loadedMetadata();
422 }
423
424 void MediaControlsApple::changedMute()
425 {
426     MediaControls::changedMute();
427
428     if (m_volumeSliderMuteButton)
429         m_volumeSliderMuteButton->changedMute();
430 }
431
432 void MediaControlsApple::changedVolume()
433 {
434     MediaControls::changedVolume();
435
436     if (m_fullScreenVolumeSlider)
437         setFullscreenSliderVolume();
438 }
439
440 void MediaControlsApple::enteredFullscreen()
441 {
442     MediaControls::enteredFullscreen();
443     m_panel->setCanBeDragged(true);
444
445     if (m_mediaController->isLiveStream()) {
446         m_seekBackButton->hide();
447         m_seekForwardButton->hide();
448         m_rewindButton->show();
449         m_returnToRealTimeButton->show();
450     } else {
451         m_seekBackButton->show();
452         m_seekForwardButton->show();
453         m_rewindButton->hide();
454         m_returnToRealTimeButton->hide();
455     }
456 }
457
458 void MediaControlsApple::exitedFullscreen()
459 {
460     m_rewindButton->show();
461     m_seekBackButton->show();
462     m_seekForwardButton->show();
463     m_returnToRealTimeButton->show();
464
465     m_panel->setCanBeDragged(false);
466
467     // We will keep using the panel, but we want it to go back to the standard position.
468     // This will matter right away because we use the panel even when not fullscreen.
469     // And if we reenter fullscreen we also want the panel in the standard position.
470     m_panel->resetPosition();
471
472     MediaControls::exitedFullscreen();
473 }
474
475 void MediaControlsApple::showVolumeSlider()
476 {
477     if (!m_mediaController->hasAudio())
478         return;
479
480     if (m_volumeSliderContainer)
481         m_volumeSliderContainer->show();
482 }
483
484 void MediaControlsApple::toggleClosedCaptionTrackList()
485 {
486     if (!m_mediaController->hasClosedCaptions())
487         return;
488
489     if (m_closedCaptionsContainer) {
490         if (m_closedCaptionsContainer->isShowing())
491             hideClosedCaptionTrackList();
492         else {
493             if (m_closedCaptionsTrackList)
494                 m_closedCaptionsTrackList->updateDisplay();
495             showClosedCaptionTrackList();
496         }
497     }
498 }
499
500 void MediaControlsApple::showClosedCaptionTrackList()
501 {
502     if (!m_closedCaptionsContainer || m_closedCaptionsContainer->isShowing())
503         return;
504
505     m_closedCaptionsContainer->show();
506
507     // Ensure the controls panel does not receive any events while the captions
508     // track list is visible as all events now need to be captured by the
509     // track list.
510     m_panel->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone);
511
512     EventListener& listener = eventListener();
513     m_closedCaptionsContainer->addEventListener(eventNames().wheelEvent, listener, true);
514
515     // Track click events in the capture phase at two levels, first at the document level
516     // such that a click outside of the <video> may dismiss the track list, second at the
517     // media controls level such that a click anywhere outside of the track list hides the
518     // track list. These two levels are necessary since it would not be possible to get a
519     // reference to the track list when handling the event outside of the shadow tree.
520     document().addEventListener(eventNames().clickEvent, listener, true);
521     addEventListener(eventNames().clickEvent, listener, true);
522 }
523
524 void MediaControlsApple::hideClosedCaptionTrackList()
525 {
526     if (!m_closedCaptionsContainer || !m_closedCaptionsContainer->isShowing())
527         return;
528
529     m_closedCaptionsContainer->hide();
530
531     // Buttons in the controls panel may now be interactive.
532     m_panel->removeInlineStyleProperty(CSSPropertyPointerEvents);
533
534     EventListener& listener = eventListener();
535     m_closedCaptionsContainer->removeEventListener(eventNames().wheelEvent, listener, true);
536     document().removeEventListener(eventNames().clickEvent, listener, true);
537     removeEventListener(eventNames().clickEvent, listener, true);
538 }
539
540 void MediaControlsApple::setFullscreenSliderVolume()
541 {
542     m_fullScreenVolumeSlider->setVolume(m_mediaController->muted() ? 0.0 : m_mediaController->volume());
543 }
544
545 bool MediaControlsApple::shouldClosedCaptionsContainerPreventPageScrolling(int wheelDeltaY)
546 {
547     int scrollTop = m_closedCaptionsContainer->scrollTop();
548     // Scrolling down.
549     if (wheelDeltaY < 0 && (scrollTop + m_closedCaptionsContainer->offsetHeight()) >= m_closedCaptionsContainer->scrollHeight())
550         return true;
551     // Scrolling up.
552     if (wheelDeltaY > 0 && scrollTop <= 0)
553         return true;
554     return false;
555 }
556
557 void MediaControlsApple::handleClickEvent(Event* event)
558 {
559     Node* currentTarget = event->currentTarget()->toNode();
560     Node* target = event->target()->toNode();
561
562     if ((currentTarget == &document() && !shadowHost()->contains(target)) || (currentTarget == this && !m_closedCaptionsContainer->contains(target))) {
563         hideClosedCaptionTrackList();
564         event->stopImmediatePropagation();
565         event->setDefaultHandled();
566     }
567 }
568
569 void MediaControlsApple::closedCaptionTracksChanged()
570 {
571     if (m_toggleClosedCaptionsButton) {
572         if (m_mediaController->hasClosedCaptions())
573             m_toggleClosedCaptionsButton->show();
574         else
575             m_toggleClosedCaptionsButton->hide();
576     }
577 }
578
579 MediaControlsAppleEventListener& MediaControlsApple::eventListener()
580 {
581     if (!m_eventListener)
582         m_eventListener = MediaControlsAppleEventListener::create(this);
583     return *m_eventListener;
584 }
585
586 // --------
587
588 void MediaControlsAppleEventListener::handleEvent(ScriptExecutionContext*, Event* event)
589 {
590     if (event->type() == eventNames().clickEvent)
591         m_mediaControls->handleClickEvent(event);
592     else if (eventNames().isWheelEventType(event->type()) && is<WheelEvent>(*event)) {
593         WheelEvent& wheelEvent = downcast<WheelEvent>(*event);
594         if (m_mediaControls->shouldClosedCaptionsContainerPreventPageScrolling(wheelEvent.wheelDeltaY()))
595             wheelEvent.preventDefault();
596     }
597 }
598
599 bool MediaControlsAppleEventListener::operator==(const EventListener& listener) const
600 {
601     if (const MediaControlsAppleEventListener* mediaControlsAppleEventListener = MediaControlsAppleEventListener::cast(&listener))
602         return m_mediaControls == mediaControlsAppleEventListener->m_mediaControls;
603     return false;
604 }
605
606 }
607
608 #endif