OSDN Git Service

Merge WebKit at r84325: Initial merge by git.
[android-x86/external-webkit.git] / Source / WebCore / html / shadow / MediaControls.cpp
1 /*
2  * Copyright (C) 2011 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
31 #include "MediaControls.h"
32
33 #include "HTMLDivElement.h"
34 #include "HTMLMediaElement.h"
35 #include "HTMLNames.h"
36 <<<<<<< HEAD
37 #include "MediaControlElements.h"
38 #include "MouseEvent.h"
39 #include "Page.h"
40 #include "RenderLayer.h"
41 #include "RenderTheme.h"
42 #include <wtf/CurrentTime.h>
43 #include <wtf/MathExtras.h>
44
45 #if PLATFORM(ANDROID)
46 #include "TouchEvent.h"
47 #define TOUCH_DELAY 4
48 #endif
49
50
51 using namespace std;
52 =======
53 >>>>>>> WebKit.org at r84325
54
55 namespace WebCore {
56
57 MediaControls::MediaControls(HTMLMediaElement* mediaElement)
58 <<<<<<< HEAD
59     : m_mediaElement(mediaElement)
60     , m_opacityAnimationTimer(this, &MediaControls::opacityAnimationTimerFired)
61     , m_opacityAnimationStartTime(0)
62     , m_opacityAnimationDuration(0)
63     , m_opacityAnimationFrom(0)
64     , m_opacityAnimationTo(1.0f)
65     , m_mouseOver(false)
66 #if PLATFORM(ANDROID)
67     , m_lastTouch(0)
68 #endif
69 {
70 }
71
72 // FIXME: This will turn into the standard element factory method once shadow DOM conversion is complete.
73 // (see https://bugs.webkit.org/show_bug.cgi?id=53020)
74 PassRefPtr<MediaControlShadowRootElement> MediaControls::create(HTMLMediaElement* mediaElement)
75 {
76     ASSERT(!m_panel);
77     ASSERT(!m_muteButton);
78     ASSERT(!m_playButton);
79     ASSERT(!m_returnToRealtimeButton);
80     ASSERT(!m_statusDisplay);
81     ASSERT(!m_timelineContainer);
82     ASSERT(!m_currentTimeDisplay);
83     ASSERT(!m_timeline);
84     ASSERT(!m_timeRemainingDisplay);
85     ASSERT(!m_seekBackButton);
86     ASSERT(!m_seekForwardButton);
87     ASSERT(!m_toggleClosedCaptionsButton);
88     ASSERT(!m_fullscreenButton);
89     ASSERT(!m_muteButton);
90     ASSERT(!m_volumeSliderContainer);
91     ASSERT(!m_volumeSlider);
92     ASSERT(!m_volumeSliderMuteButton);
93     ASSERT(!m_fullScreenMinVolumeButton);
94     ASSERT(!m_fullScreenMaxVolumeButton);
95     ASSERT(!m_fullScreenVolumeSlider);
96
97     RefPtr<MediaControlShadowRootElement> controls = MediaControlShadowRootElement::create(mediaElement);
98
99     m_panel = MediaControlPanelElement::create(mediaElement);
100
101     m_rewindButton = MediaControlRewindButtonElement::create(mediaElement);
102     m_rewindButton->attachToParent(m_panel.get());
103
104     m_playButton = MediaControlPlayButtonElement::create(mediaElement);
105     m_playButton->attachToParent(m_panel.get());
106
107     m_returnToRealtimeButton = MediaControlReturnToRealtimeButtonElement::create(mediaElement);
108     m_returnToRealtimeButton->attachToParent(m_panel.get());
109
110     m_statusDisplay = MediaControlStatusDisplayElement::create(mediaElement);
111     m_statusDisplay->attachToParent(m_panel.get());
112
113     m_timelineContainer = MediaControlTimelineContainerElement::create(mediaElement);
114
115     m_currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(mediaElement);
116     m_currentTimeDisplay->attachToParent(m_timelineContainer.get());
117
118     m_timeline = MediaControlTimelineElement::create(mediaElement);
119     m_timeline->attachToParent(m_timelineContainer.get());
120
121     m_timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(mediaElement);
122     m_timeRemainingDisplay->attachToParent(m_timelineContainer.get());
123
124     m_timelineContainer->attachToParent(m_panel.get());
125
126     m_seekBackButton = MediaControlSeekBackButtonElement::create(mediaElement);
127     m_seekBackButton->attachToParent(m_panel.get());
128
129     m_seekForwardButton = MediaControlSeekForwardButtonElement::create(mediaElement);
130     m_seekForwardButton->attachToParent(m_panel.get());
131
132     m_toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(mediaElement);
133     m_toggleClosedCaptionsButton->attachToParent(m_panel.get());
134
135     m_fullscreenButton = MediaControlFullscreenButtonElement::create(mediaElement);
136     m_fullscreenButton->attachToParent(m_panel.get());
137
138     m_muteButton = MediaControlPanelMuteButtonElement::create(mediaElement);
139     m_muteButton->attachToParent(m_panel.get());
140
141     m_volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(mediaElement);
142
143     m_volumeSlider = MediaControlVolumeSliderElement::create(mediaElement);
144     m_volumeSlider->attachToParent(m_volumeSliderContainer.get());
145
146     m_volumeSliderMuteButton = MediaControlVolumeSliderMuteButtonElement::create(mediaElement);
147     m_volumeSliderMuteButton->attachToParent(m_volumeSliderContainer.get());
148
149     m_volumeSliderContainer->attachToParent(m_panel.get());
150     
151     // FIXME: These controls, and others, should be created dynamically when needed, instead of 
152     // always created.  <http://webkit.org/b/57163>
153     m_fullScreenMinVolumeButton = MediaControlFullscreenVolumeMinButtonElement::create(mediaElement);
154     m_fullScreenMinVolumeButton->attachToParent(m_panel.get());
155     
156     m_fullScreenVolumeSlider = MediaControlFullscreenVolumeSliderElement::create(mediaElement);
157     m_fullScreenVolumeSlider->attachToParent(m_panel.get());
158     
159     m_fullScreenMaxVolumeButton = MediaControlFullscreenVolumeMaxButtonElement::create(mediaElement);
160     m_fullScreenMaxVolumeButton->attachToParent(m_panel.get());
161     
162     m_panel->attachToParent(controls.get());
163     return controls.release();
164 }
165
166 void MediaControls::reset()
167 {
168     update();
169 }
170
171 void MediaControls::playbackProgressed()
172 {
173     if (m_timeline)
174         m_timeline->update(false);
175     updateTimeDisplay();
176 }
177
178 void MediaControls::playbackStarted()
179 {
180     playbackProgressed();
181 }
182
183 void MediaControls::playbackStopped()
184 {
185     playbackProgressed();
186 }
187
188 void MediaControls::changedMute()
189 {
190     update();
191 }
192
193 void MediaControls::changedVolume()
194 {
195     update();
196 }
197
198 void MediaControls::changedClosedCaptionsVisibility()
199 {
200     update();
201 }
202
203 void MediaControls::updateStyle()
204 {
205     if (!m_controlsShadowRoot)
206         return;
207
208     if (m_panel)
209         m_panel->updateStyle();
210     if (m_muteButton)
211         m_muteButton->updateStyle();
212     if (m_playButton)
213         m_playButton->updateStyle();
214     if (m_seekBackButton)
215         m_seekBackButton->updateStyle();
216     if (m_seekForwardButton)
217         m_seekForwardButton->updateStyle();
218     if (m_rewindButton)
219         m_rewindButton->updateStyle();
220     if (m_returnToRealtimeButton)
221         m_returnToRealtimeButton->updateStyle();
222     if (m_toggleClosedCaptionsButton)
223         m_toggleClosedCaptionsButton->updateStyle();
224     if (m_statusDisplay)
225         m_statusDisplay->updateStyle();
226     if (m_timelineContainer)
227         m_timelineContainer->updateStyle();
228     if (m_timeline)
229         m_timeline->updateStyle();
230     if (m_fullscreenButton)
231         m_fullscreenButton->updateStyle();
232     if (m_currentTimeDisplay)
233         m_currentTimeDisplay->updateStyle();
234     if (m_timeRemainingDisplay)
235         m_timeRemainingDisplay->updateStyle();
236     if (m_volumeSliderContainer)
237         m_volumeSliderContainer->updateStyle();
238     if (m_volumeSliderMuteButton)
239         m_volumeSliderMuteButton->updateStyle();
240     if (m_volumeSlider)
241         m_volumeSlider->updateStyle();
242     if (m_fullScreenMinVolumeButton)
243         m_fullScreenMinVolumeButton->updateStyle();
244     if (m_fullScreenVolumeSlider)
245         m_fullScreenVolumeSlider->updateStyle();
246     if (m_fullScreenMaxVolumeButton)
247         m_fullScreenMaxVolumeButton->updateStyle();
248 }
249
250 void MediaControls::destroy()
251 {
252     ASSERT(m_mediaElement->renderer());
253
254     if (m_controlsShadowRoot && m_controlsShadowRoot->renderer()) {
255
256         // detach the panel before removing the shadow renderer to prevent a crash in m_controlsShadowRoot->detach() 
257         //  when display: style changes
258         m_panel->detach();
259
260         m_mediaElement->renderer()->removeChild(m_controlsShadowRoot->renderer());
261         m_controlsShadowRoot->detach();
262         m_controlsShadowRoot = 0;
263     }
264 }
265
266 void MediaControls::update()
267 {
268     HTMLMediaElement* media = m_mediaElement;
269     if (!media->controls() || !media->inActiveDocument()) {
270         if (m_controlsShadowRoot) {
271             m_controlsShadowRoot->detach();
272             m_panel = 0;
273             m_muteButton = 0;
274             m_playButton = 0;
275             m_statusDisplay = 0;
276             m_timelineContainer = 0;
277             m_timeline = 0;
278             m_seekBackButton = 0;
279             m_seekForwardButton = 0;
280             m_rewindButton = 0;
281             m_returnToRealtimeButton = 0;
282             m_currentTimeDisplay = 0;
283             m_timeRemainingDisplay = 0;
284             m_fullscreenButton = 0;
285             m_volumeSliderContainer = 0;
286             m_volumeSlider = 0;
287             m_volumeSliderMuteButton = 0;
288             m_controlsShadowRoot = 0;
289             m_toggleClosedCaptionsButton = 0;
290             m_fullScreenMinVolumeButton = 0;
291             m_fullScreenVolumeSlider = 0;
292             m_fullScreenMaxVolumeButton = 0;
293         }
294         m_opacityAnimationTo = 1.0f;
295         m_opacityAnimationTimer.stop();
296         return;
297     }
298
299     if (!m_controlsShadowRoot) {
300         m_controlsShadowRoot = create(m_mediaElement);
301         m_mediaElement->renderer()->addChild(m_controlsShadowRoot->renderer());
302         m_panel->attach();
303     }
304
305     if (m_panel) {
306         // update() might alter the opacity of the element, especially if we are in the middle
307         // of an animation. This is the only element concerned as we animate only this element.
308         float opacityBeforeChangingStyle = m_panel->renderer() ? m_panel->renderer()->style()->opacity() : 0;
309         m_panel->update();
310         changeOpacity(m_panel.get(), opacityBeforeChangingStyle);
311     }
312     if (m_muteButton)
313         m_muteButton->update();
314     if (m_playButton)
315         m_playButton->update();
316     if (m_timelineContainer)
317         m_timelineContainer->update();
318     if (m_volumeSliderContainer)
319         m_volumeSliderContainer->update();
320     if (m_timeline)
321         m_timeline->update();
322     if (m_currentTimeDisplay)
323         m_currentTimeDisplay->update();
324     if (m_timeRemainingDisplay)
325         m_timeRemainingDisplay->update();
326     if (m_seekBackButton)
327         m_seekBackButton->update();
328     if (m_seekForwardButton)
329         m_seekForwardButton->update();
330     if (m_rewindButton)
331         m_rewindButton->update();
332     if (m_returnToRealtimeButton)
333         m_returnToRealtimeButton->update();
334     if (m_toggleClosedCaptionsButton)
335         m_toggleClosedCaptionsButton->update();
336     if (m_statusDisplay)
337         m_statusDisplay->update();
338     if (m_fullscreenButton)
339         m_fullscreenButton->update();
340     if (m_volumeSlider)
341         m_volumeSlider->update();
342     if (m_volumeSliderMuteButton)
343         m_volumeSliderMuteButton->update();
344     if (m_fullScreenMinVolumeButton)
345         m_fullScreenMinVolumeButton->update();
346     if (m_fullScreenVolumeSlider)
347         m_fullScreenVolumeSlider->update();
348     if (m_fullScreenMaxVolumeButton)
349         m_fullScreenMaxVolumeButton->update();
350     updateTimeDisplay();
351     updateControlVisibility();
352 }
353
354 void MediaControls::updateTimeDisplay()
355 {
356     ASSERT(m_mediaElement->renderer());
357
358     if (!m_currentTimeDisplay || !m_currentTimeDisplay->renderer() || m_currentTimeDisplay->renderer()->style()->display() == NONE || m_mediaElement->renderer()->style()->visibility() != VISIBLE)
359         return;
360
361     float now = m_mediaElement->currentTime();
362     float duration = m_mediaElement->duration();
363
364     // Allow the theme to format the time
365     ExceptionCode ec;
366     m_currentTimeDisplay->setInnerText(m_mediaElement->renderer()->theme()->formatMediaControlsCurrentTime(now, duration), ec);
367     m_currentTimeDisplay->setCurrentValue(now);
368     m_timeRemainingDisplay->setInnerText(m_mediaElement->renderer()->theme()->formatMediaControlsRemainingTime(now, duration), ec);
369     m_timeRemainingDisplay->setCurrentValue(now - duration);
370 }
371
372 RenderBox* MediaControls::renderBox()
373 {
374     return m_controlsShadowRoot ? m_controlsShadowRoot->renderBox() : 0;
375 }
376
377 void MediaControls::updateControlVisibility()
378 {
379     if (!m_panel || !m_panel->renderer())
380         return;
381
382     // Don't fade for audio controls.
383     HTMLMediaElement* media = m_mediaElement;
384     if (!media->hasVideo())
385         return;
386
387     ASSERT(media->renderer());
388
389     // Don't fade if the media element is not visible
390     if (media->renderer()->style()->visibility() != VISIBLE)
391         return;
392
393 #if PLATFORM(ANDROID)
394     if (WTF::currentTime() - m_lastTouch > TOUCH_DELAY)
395         m_mouseOver = false;
396     else
397         m_mouseOver = true;
398 #endif
399     
400     bool shouldHideController = !m_mouseOver && !media->canPlay();
401
402     // Do fading manually, css animations don't work with shadow trees
403
404     float animateFrom = m_panel->renderer()->style()->opacity();
405     float animateTo = shouldHideController ? 0.0f : 1.0f;
406
407     if (animateFrom == animateTo)
408         return;
409
410     if (m_opacityAnimationTimer.isActive()) {
411         if (m_opacityAnimationTo == animateTo)
412             return;
413         m_opacityAnimationTimer.stop();
414     }
415
416     if (animateFrom < animateTo)
417         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeInDuration();
418     else
419         m_opacityAnimationDuration = m_panel->renderer()->theme()->mediaControlsFadeOutDuration();
420
421     m_opacityAnimationFrom = animateFrom;
422     m_opacityAnimationTo = animateTo;
423
424     m_opacityAnimationStartTime = currentTime();
425     m_opacityAnimationTimer.startRepeating(cOpacityAnimationRepeatDelay);
426 }
427
428 void MediaControls::changeOpacity(HTMLElement* e, float opacity)
429 {
430     if (!e || !e->renderer() || !e->renderer()->style())
431         return;
432     RefPtr<RenderStyle> s = RenderStyle::clone(e->renderer()->style());
433     s->setOpacity(opacity);
434     // z-index can't be auto if opacity is used
435     s->setZIndex(0);
436     e->renderer()->setStyle(s.release());
437 }
438
439 void MediaControls::opacityAnimationTimerFired(Timer<MediaControls>*)
440 {
441     double time = currentTime() - m_opacityAnimationStartTime;
442     if (time >= m_opacityAnimationDuration) {
443         time = m_opacityAnimationDuration;
444         m_opacityAnimationTimer.stop();
445     }
446     float opacity = narrowPrecisionToFloat(m_opacityAnimationFrom + (m_opacityAnimationTo - m_opacityAnimationFrom) * time / m_opacityAnimationDuration);
447     changeOpacity(m_panel.get(), opacity);
448 }
449
450 void MediaControls::updateVolumeSliderContainer(bool visible)
451 {
452     if (!m_mediaElement->hasAudio() || !m_volumeSliderContainer || !m_volumeSlider)
453         return;
454
455     if (visible && !m_volumeSliderContainer->isVisible()) {
456         if (!m_muteButton || !m_muteButton->renderer() || !m_muteButton->renderBox())
457             return;
458
459         RefPtr<RenderStyle> s = m_volumeSliderContainer->styleForElement();
460         m_volumeSliderContainer->setVisible(true);
461         m_volumeSliderContainer->update();
462         m_volumeSlider->update();
463     } else if (!visible && m_volumeSliderContainer->isVisible()) {
464         m_volumeSliderContainer->setVisible(false);
465         m_volumeSliderContainer->updateStyle();
466     }
467 }
468
469 void MediaControls::forwardEvent(Event* event)
470 {
471 #if PLATFORM(ANDROID)
472     if (event->isMouseEvent())
473         updateLastTouch();
474 #if ENABLE(TOUCH_EVENTS)
475     if (event->isTouchEvent())
476         updateLastTouch();
477 #endif
478 #endif
479
480     ASSERT(m_mediaElement->renderer());
481
482     if (event->isMouseEvent() && m_controlsShadowRoot) {
483         MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
484         IntPoint point(mouseEvent->absoluteLocation());
485
486         bool defaultHandled = false;
487         if (m_volumeSliderMuteButton && m_volumeSliderMuteButton->hitTest(point)) {
488             m_volumeSliderMuteButton->defaultEventHandler(event);
489             defaultHandled = event->defaultHandled();
490         }
491
492         bool showVolumeSlider = false;
493         if (!defaultHandled && m_muteButton && m_muteButton->hitTest(point)) {
494             m_muteButton->defaultEventHandler(event);
495             if (event->type() != eventNames().mouseoutEvent)
496                 showVolumeSlider = true;
497         }
498
499         if (m_volumeSliderContainer && m_volumeSliderContainer->hitTest(point))
500             showVolumeSlider = true;
501
502         if (m_volumeSlider && m_volumeSlider->hitTest(point)) {
503             m_volumeSlider->defaultEventHandler(event);
504             showVolumeSlider = true;
505         }
506
507         updateVolumeSliderContainer(showVolumeSlider);
508
509         if (m_playButton && m_playButton->hitTest(point))
510             m_playButton->defaultEventHandler(event);
511
512         if (m_seekBackButton && m_seekBackButton->hitTest(point))
513             m_seekBackButton->defaultEventHandler(event);
514
515         if (m_seekForwardButton && m_seekForwardButton->hitTest(point))
516             m_seekForwardButton->defaultEventHandler(event);
517
518         if (m_rewindButton && m_rewindButton->hitTest(point))
519             m_rewindButton->defaultEventHandler(event);
520
521         if (m_returnToRealtimeButton && m_returnToRealtimeButton->hitTest(point))
522             m_returnToRealtimeButton->defaultEventHandler(event);
523
524        if (m_toggleClosedCaptionsButton && m_toggleClosedCaptionsButton->hitTest(point))
525             m_toggleClosedCaptionsButton->defaultEventHandler(event);
526
527         if (m_timeline && m_timeline->hitTest(point))
528             m_timeline->defaultEventHandler(event);
529
530         if (m_fullscreenButton && m_fullscreenButton->hitTest(point))
531             m_fullscreenButton->defaultEventHandler(event);
532
533         if (event->type() == eventNames().mouseoverEvent) {
534             m_mouseOver = true;
535             updateControlVisibility();
536         }
537         if (event->type() == eventNames().mouseoutEvent) {
538             // When the scrollbar thumb captures mouse events, we should treat the mouse as still being over our renderer if the new target is a descendant
539             Node* mouseOverNode = mouseEvent->relatedTarget() ? mouseEvent->relatedTarget()->toNode() : 0;
540             RenderObject* mouseOverRenderer = mouseOverNode ? mouseOverNode->renderer() : 0;
541             m_mouseOver = mouseOverRenderer && mouseOverRenderer->isDescendantOf(m_mediaElement->renderer());
542             updateControlVisibility();
543         }
544     }
545 #if PLATFORM(ANDROID) && ENABLE(TOUCH_EVENTS)
546     // We want to process touch events landing on the timeline so that the user
547     // can drag the scrollbar thumb with their finger.
548     else if (event->isTouchEvent() && m_controlsShadowRoot) {
549         TouchEvent* touchEvent = static_cast<TouchEvent*>(event);
550         if (touchEvent->touches() && touchEvent->touches()->item(0)) {
551             IntPoint point;
552             point.setX(touchEvent->touches()->item(0)->pageX());
553             point.setY(touchEvent->touches()->item(0)->pageY());
554             if (m_timeline && m_timeline->hitTest(point))
555                 m_timeline->defaultEventHandler(event);
556         }
557     }
558 #endif
559 =======
560     : HTMLDivElement(HTMLNames::divTag, mediaElement->document())
561 {
562 >>>>>>> WebKit.org at r84325
563 }
564
565 #if PLATFORM(ANDROID)
566 void MediaControls::updateLastTouch()
567 {
568     m_lastTouch = WTF::currentTime();
569 }
570 #endif
571
572 }
573
574 #endif