69dce0633ba096b0699b2ffd3f32e149c3ca162c
[WebKit.git] / Source / WebCore / html / shadow / MediaControlsBlackBerry.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
3  * Copyright (C) 2011 Google Inc. All rights reserved.
4  * Copyright (C) 2012 Research In Motion Limited. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include "config.h"
29
30 #if ENABLE(VIDEO)
31 #include "MediaControlsBlackBerry.h"
32
33 #include "Chrome.h"
34 #include "DOMTokenList.h"
35 #include "ExceptionCodePlaceholder.h"
36 #include "FloatConversion.h"
37 #include "Frame.h"
38 #include "HTMLMediaElement.h"
39 #include "HTMLNames.h"
40 #include "MediaControlElements.h"
41 #include "MouseEvent.h"
42 #include "Page.h"
43 #include "RenderDeprecatedFlexibleBox.h"
44 #include "RenderSlider.h"
45 #include "RenderTheme.h"
46 #include "Settings.h"
47 #include "Text.h"
48
49 #if ENABLE(VIDEO_TRACK)
50 #include "TextTrackCue.h"
51 #endif
52
53 using namespace std;
54
55 namespace WebCore {
56
57 using namespace HTMLNames;
58
59 static const double timeWithoutMouseMovementBeforeHidingControls = 3;
60
61 inline MediaControlButtonGroupContainerElement::MediaControlButtonGroupContainerElement(Document* document)
62     : MediaControlDivElement(document, MediaControlsPanel)
63 {
64 }
65
66 PassRefPtr<MediaControlButtonGroupContainerElement> MediaControlButtonGroupContainerElement::create(Document* document)
67 {
68     RefPtr<MediaControlButtonGroupContainerElement> element = adoptRef(new MediaControlButtonGroupContainerElement(document));
69     return element.release();
70 }
71
72 const AtomicString& MediaControlButtonGroupContainerElement::shadowPseudoId() const
73 {
74     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-button-group-container", AtomicString::ConstructFromLiteral));
75     return id;
76 }
77
78 inline MediaControlTimeDisplayContainerElement::MediaControlTimeDisplayContainerElement(Document* document)
79     : MediaControlDivElement(document, MediaControlsPanel)
80 {
81 }
82
83 PassRefPtr<MediaControlTimeDisplayContainerElement> MediaControlTimeDisplayContainerElement::create(Document* document)
84 {
85     RefPtr<MediaControlTimeDisplayContainerElement> element = adoptRef(new MediaControlTimeDisplayContainerElement(document));
86     return element.release();
87 }
88
89 const AtomicString& MediaControlTimeDisplayContainerElement::shadowPseudoId() const
90 {
91     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-time-display-container", AtomicString::ConstructFromLiteral));
92     return id;
93 }
94
95 MediaControlEmbeddedPanelElement::MediaControlEmbeddedPanelElement(Document* document)
96     : MediaControlDivElement(document, MediaControlsPanel)
97     , m_canBeDragged(false)
98     , m_isBeingDragged(false)
99     , m_isDisplayed(false)
100     , m_opaque(true)
101     , m_transitionTimer(this, &MediaControlEmbeddedPanelElement::transitionTimerFired)
102 {
103 }
104
105 PassRefPtr<MediaControlEmbeddedPanelElement> MediaControlEmbeddedPanelElement::create(Document* document)
106 {
107     return adoptRef(new MediaControlEmbeddedPanelElement(document));
108 }
109
110 const AtomicString& MediaControlEmbeddedPanelElement::shadowPseudoId() const
111 {
112     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-embedded-panel", AtomicString::ConstructFromLiteral));
113     return id;
114 }
115
116 void MediaControlEmbeddedPanelElement::startDrag(const LayoutPoint& eventLocation)
117 {
118     if (!m_canBeDragged)
119         return;
120
121     if (m_isBeingDragged)
122         return;
123
124     RenderObject* renderer = this->renderer();
125     if (!renderer || !renderer->isBox())
126         return;
127
128     Frame* frame = document()->frame();
129     if (!frame)
130         return;
131
132     m_lastDragEventLocation = eventLocation;
133
134     frame->eventHandler()->setCapturingMouseEventsNode(this);
135
136     m_isBeingDragged = true;
137 }
138
139 void MediaControlEmbeddedPanelElement::continueDrag(const LayoutPoint& eventLocation)
140 {
141     if (!m_isBeingDragged)
142         return;
143
144     LayoutSize distanceDragged = eventLocation - m_lastDragEventLocation;
145     m_cumulativeDragOffset.move(distanceDragged);
146     m_lastDragEventLocation = eventLocation;
147     setPosition(m_cumulativeDragOffset);
148 }
149
150 void MediaControlEmbeddedPanelElement::endDrag()
151 {
152     if (!m_isBeingDragged)
153         return;
154
155     m_isBeingDragged = false;
156
157     Frame* frame = document()->frame();
158     if (!frame)
159         return;
160
161     frame->eventHandler()->setCapturingMouseEventsNode(0);
162 }
163
164 void MediaControlEmbeddedPanelElement::startTimer()
165 {
166     stopTimer();
167
168     // The timer is required to set the property display:'none' on the panel,
169     // such that captions are correctly displayed at the bottom of the video
170     // at the end of the fadeout transition.
171     double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
172     m_transitionTimer.startOneShot(duration);
173 }
174
175 void MediaControlEmbeddedPanelElement::stopTimer()
176 {
177     if (m_transitionTimer.isActive())
178         m_transitionTimer.stop();
179 }
180
181 void MediaControlEmbeddedPanelElement::transitionTimerFired(Timer<MediaControlEmbeddedPanelElement>*)
182 {
183     if (!m_opaque)
184         hide();
185
186     stopTimer();
187 }
188
189 void MediaControlEmbeddedPanelElement::setPosition(const LayoutPoint& position)
190 {
191     double left = position.x();
192     double top = position.y();
193
194     // Set the left and top to control the panel's position; this depends on it being absolute positioned.
195     // Set the margin to zero since the position passed in will already include the effect of the margin.
196     setInlineStyleProperty(CSSPropertyLeft, left, CSSPrimitiveValue::CSS_PX);
197     setInlineStyleProperty(CSSPropertyTop, top, CSSPrimitiveValue::CSS_PX);
198     setInlineStyleProperty(CSSPropertyMarginLeft, 0.0, CSSPrimitiveValue::CSS_PX);
199     setInlineStyleProperty(CSSPropertyMarginTop, 0.0, CSSPrimitiveValue::CSS_PX);
200
201     classList()->add("dragged", IGNORE_EXCEPTION);
202 }
203
204 void MediaControlEmbeddedPanelElement::resetPosition()
205 {
206     removeInlineStyleProperty(CSSPropertyLeft);
207     removeInlineStyleProperty(CSSPropertyTop);
208     removeInlineStyleProperty(CSSPropertyMarginLeft);
209     removeInlineStyleProperty(CSSPropertyMarginTop);
210
211     classList()->remove("dragged", IGNORE_EXCEPTION);
212
213     m_cumulativeDragOffset.setX(0);
214     m_cumulativeDragOffset.setY(0);
215 }
216
217 void MediaControlEmbeddedPanelElement::makeOpaque()
218 {
219     if (m_opaque)
220         return;
221
222     double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeInDuration() : 0;
223
224     setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
225     setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
226     setInlineStyleProperty(CSSPropertyOpacity, 1.0, CSSPrimitiveValue::CSS_NUMBER);
227
228     m_opaque = true;
229
230     if (m_isDisplayed)
231         show();
232 }
233
234 void MediaControlEmbeddedPanelElement::makeTransparent()
235 {
236     if (!m_opaque)
237         return;
238
239     double duration = document()->page() ? document()->page()->theme()->mediaControlsFadeOutDuration() : 0;
240
241     setInlineStyleProperty(CSSPropertyWebkitTransitionProperty, CSSPropertyOpacity);
242     setInlineStyleProperty(CSSPropertyWebkitTransitionDuration, duration, CSSPrimitiveValue::CSS_S);
243     setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
244
245     m_opaque = false;
246     startTimer();
247 }
248
249 void MediaControlEmbeddedPanelElement::defaultEventHandler(Event* event)
250 {
251     MediaControlDivElement::defaultEventHandler(event);
252
253     if (event->isMouseEvent()) {
254         LayoutPoint location = static_cast<MouseEvent*>(event)->absoluteLocation();
255         if (event->type() == eventNames().mousedownEvent && event->target() == this) {
256             startDrag(location);
257             event->setDefaultHandled();
258         } else if (event->type() == eventNames().mousemoveEvent && m_isBeingDragged)
259             continueDrag(location);
260         else if (event->type() == eventNames().mouseupEvent && m_isBeingDragged) {
261             continueDrag(location);
262             endDrag();
263             event->setDefaultHandled();
264         }
265     }
266 }
267
268 void MediaControlEmbeddedPanelElement::setCanBeDragged(bool canBeDragged)
269 {
270     if (m_canBeDragged == canBeDragged)
271         return;
272
273     m_canBeDragged = canBeDragged;
274
275     if (!canBeDragged)
276         endDrag();
277 }
278
279 void MediaControlEmbeddedPanelElement::setIsDisplayed(bool isDisplayed)
280 {
281     m_isDisplayed = isDisplayed;
282 }
283
284 inline MediaControlFullscreenTimeDisplayContainerElement::MediaControlFullscreenTimeDisplayContainerElement(Document* document)
285     : MediaControlDivElement(document, MediaControlsPanel)
286 {
287 }
288
289 PassRefPtr<MediaControlFullscreenTimeDisplayContainerElement> MediaControlFullscreenTimeDisplayContainerElement::create(Document* document)
290 {
291     RefPtr<MediaControlFullscreenTimeDisplayContainerElement> element = adoptRef(new MediaControlFullscreenTimeDisplayContainerElement(document));
292     return element.release();
293 }
294
295 const AtomicString& MediaControlFullscreenTimeDisplayContainerElement::shadowPseudoId() const
296 {
297     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-display-container", AtomicString::ConstructFromLiteral));
298     return id;
299 }
300
301 inline MediaControlFullscreenButtonContainerElement::MediaControlFullscreenButtonContainerElement(Document* document)
302     : MediaControlDivElement(document, MediaControlsPanel)
303 {
304 }
305
306 PassRefPtr<MediaControlFullscreenButtonContainerElement> MediaControlFullscreenButtonContainerElement::create(Document* document)
307 {
308     RefPtr<MediaControlFullscreenButtonContainerElement> element = adoptRef(new MediaControlFullscreenButtonContainerElement(document));
309     return element.release();
310 }
311
312 const AtomicString& MediaControlFullscreenButtonContainerElement::shadowPseudoId() const
313 {
314     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-container", AtomicString::ConstructFromLiteral));
315     return id;
316 }
317
318 inline MediaControlFullscreenButtonDividerElement::MediaControlFullscreenButtonDividerElement(Document* document)
319     : MediaControlDivElement(document, MediaRewindButton)
320 {
321 }
322
323 PassRefPtr<MediaControlFullscreenButtonDividerElement> MediaControlFullscreenButtonDividerElement::create(Document* document)
324 {
325     RefPtr<MediaControlFullscreenButtonDividerElement> element = adoptRef(new MediaControlFullscreenButtonDividerElement(document));
326     return element.release();
327 }
328
329 const AtomicString& MediaControlFullscreenButtonDividerElement::shadowPseudoId() const
330 {
331     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-button-divider", AtomicString::ConstructFromLiteral));
332     return id;
333 }
334
335 inline MediaControlPlayButtonContainerElement::MediaControlPlayButtonContainerElement(Document* document)
336     : MediaControlDivElement(document, MediaControlsPanel)
337 {
338 }
339
340 PassRefPtr<MediaControlPlayButtonContainerElement> MediaControlPlayButtonContainerElement::create(Document* document)
341 {
342     RefPtr<MediaControlPlayButtonContainerElement> element = adoptRef(new MediaControlPlayButtonContainerElement(document));
343     return element.release();
344 }
345
346 const AtomicString& MediaControlPlayButtonContainerElement::shadowPseudoId() const
347 {
348     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-play-button-container", AtomicString::ConstructFromLiteral));
349     return id;
350 }
351
352 inline MediaControlPlaceholderElement::MediaControlPlaceholderElement(Document* document)
353     : MediaControlDivElement(document, MediaControlsPanel)
354 {
355 }
356
357 PassRefPtr<MediaControlPlaceholderElement> MediaControlPlaceholderElement::create(Document* document)
358 {
359     RefPtr<MediaControlPlaceholderElement> element = adoptRef(new MediaControlPlaceholderElement(document));
360     return element.release();
361 }
362
363 const AtomicString& MediaControlPlaceholderElement::shadowPseudoId() const
364 {
365     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-placeholder", AtomicString::ConstructFromLiteral));
366     return id;
367 }
368
369 inline MediaControlFullscreenPlayButtonElement::MediaControlFullscreenPlayButtonElement(Document* document)
370     : MediaControlInputElement(document, MediaPlayButton)
371 {
372 }
373
374 PassRefPtr<MediaControlFullscreenPlayButtonElement> MediaControlFullscreenPlayButtonElement::create(Document* document)
375 {
376     RefPtr<MediaControlFullscreenPlayButtonElement> button = adoptRef(new MediaControlFullscreenPlayButtonElement(document));
377     button->ensureUserAgentShadowRoot();
378     button->setType("button");
379     return button.release();
380 }
381
382 void MediaControlFullscreenPlayButtonElement::defaultEventHandler(Event* event)
383 {
384     if (event->type() == eventNames().clickEvent) {
385         if (mediaController()->canPlay())
386             mediaController()->play();
387         else
388             mediaController()->pause();
389         updateDisplayType();
390         event->setDefaultHandled();
391     }
392     HTMLInputElement::defaultEventHandler(event);
393 }
394
395 void MediaControlFullscreenPlayButtonElement::updateDisplayType()
396 {
397     setDisplayType(mediaController()->canPlay() ? MediaPlayButton : MediaPauseButton);
398 }
399
400 const AtomicString& MediaControlFullscreenPlayButtonElement::shadowPseudoId() const
401 {
402     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-play-button", AtomicString::ConstructFromLiteral));
403     return id;
404 }
405
406 inline MediaControlFullscreenFullscreenButtonElement::MediaControlFullscreenFullscreenButtonElement(Document* document)
407     : MediaControlInputElement(document, MediaExitFullscreenButton)
408 {
409 }
410
411 PassRefPtr<MediaControlFullscreenFullscreenButtonElement> MediaControlFullscreenFullscreenButtonElement::create(Document* document)
412 {
413     RefPtr<MediaControlFullscreenFullscreenButtonElement> button = adoptRef(new MediaControlFullscreenFullscreenButtonElement(document));
414     button->ensureUserAgentShadowRoot();
415     button->setType("button");
416     button->hide();
417     return button.release();
418 }
419
420 void MediaControlFullscreenFullscreenButtonElement::defaultEventHandler(Event* event)
421 {
422     if (event->type() == eventNames().clickEvent) {
423 #if ENABLE(FULLSCREEN_API)
424         // Only use the new full screen API if the fullScreenEnabled setting has 
425         // been explicitly enabled. Otherwise, use the old fullscreen API. This
426         // allows apps which embed a WebView to retain the existing full screen
427         // video implementation without requiring them to implement their own full 
428         // screen behavior.
429         if (document()->settings() && document()->settings()->fullScreenEnabled()) {
430             if (document()->webkitIsFullScreen() && document()->webkitCurrentFullScreenElement() == toParentMediaElement(this))
431                 document()->webkitCancelFullScreen();
432             else
433                 document()->requestFullScreenForElement(toParentMediaElement(this), 0, Document::ExemptIFrameAllowFullScreenRequirement);
434         } else
435 #endif
436             mediaController()->enterFullscreen();
437         event->setDefaultHandled();
438     }
439     HTMLInputElement::defaultEventHandler(event);
440 }
441
442 const AtomicString& MediaControlFullscreenFullscreenButtonElement::shadowPseudoId() const
443 {
444     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-fullscreen-button", AtomicString::ConstructFromLiteral));
445     return id;
446 }
447
448 void MediaControlFullscreenFullscreenButtonElement::setIsFullscreen(bool isFullscreen)
449 {
450     setDisplayType(MediaExitFullscreenButton);
451 }
452
453 inline MediaControlFullscreenTimelineContainerElement::MediaControlFullscreenTimelineContainerElement(Document* document)
454     : MediaControlDivElement(document, MediaTimelineContainer)
455 {
456 }
457
458 PassRefPtr<MediaControlFullscreenTimelineContainerElement> MediaControlFullscreenTimelineContainerElement::create(Document* document)
459 {
460     RefPtr<MediaControlFullscreenTimelineContainerElement> element = adoptRef(new MediaControlFullscreenTimelineContainerElement(document));
461     element->hide();
462     return element.release();
463 }
464
465 const AtomicString& MediaControlFullscreenTimelineContainerElement::shadowPseudoId() const
466 {
467     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline-container", AtomicString::ConstructFromLiteral));
468     return id;
469 }
470
471 MediaControlFullscreenTimelineElement::MediaControlFullscreenTimelineElement(Document* document, MediaControls* controls)
472     : MediaControlInputElement(document, MediaSlider)
473     , m_controls(controls)
474 {
475 }
476
477 PassRefPtr<MediaControlFullscreenTimelineElement> MediaControlFullscreenTimelineElement::create(Document* document, MediaControls* controls)
478 {
479     ASSERT(controls);
480
481     RefPtr<MediaControlFullscreenTimelineElement> timeline = adoptRef(new MediaControlFullscreenTimelineElement(document, controls));
482     timeline->ensureUserAgentShadowRoot();
483     timeline->setType("range");
484     timeline->setAttribute(precisionAttr, "float");
485     return timeline.release();
486 }
487
488 void MediaControlFullscreenTimelineElement::defaultEventHandler(Event* event)
489 {
490     // Left button is 0. Rejects mouse events not from left button.
491     if (event->isMouseEvent() && static_cast<MouseEvent*>(event)->button())
492         return;
493
494     if (!attached())
495         return;
496
497     if (event->type() == eventNames().mousedownEvent)
498         mediaController()->beginScrubbing();
499
500     if (event->type() == eventNames().mouseupEvent)
501         mediaController()->endScrubbing();
502
503     MediaControlInputElement::defaultEventHandler(event);
504
505     if (event->type() == eventNames().mouseoverEvent || event->type() == eventNames().mouseoutEvent || event->type() == eventNames().mousemoveEvent)
506         return;
507
508     float time = narrowPrecisionToFloat(value().toDouble());
509     if (event->type() == eventNames().inputEvent && time != mediaController()->currentTime())
510         mediaController()->setCurrentTime(time, IGNORE_EXCEPTION);
511
512     RenderSlider* slider = toRenderSlider(renderer());
513     if (slider && slider->inDragMode())
514         m_controls->updateCurrentTimeDisplay();
515 }
516
517 bool MediaControlFullscreenTimelineElement::willRespondToMouseClickEvents()
518 {
519     if (!attached())
520         return false;
521
522     return true;
523 }
524
525 void MediaControlFullscreenTimelineElement::setPosition(float currentTime)
526 {
527     setValue(String::number(currentTime));
528 }
529
530 void MediaControlFullscreenTimelineElement::setDuration(float duration)
531 {
532     setAttribute(maxAttr, String::number(isfinite(duration) ? duration : 0));
533 }
534
535 const AtomicString& MediaControlFullscreenTimelineElement::shadowPseudoId() const
536 {
537     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-timeline", AtomicString::ConstructFromLiteral));
538     return id;
539 }
540
541 PassRefPtr<MediaControlFullscreenTimeRemainingDisplayElement> MediaControlFullscreenTimeRemainingDisplayElement::create(Document* document)
542 {
543     return adoptRef(new MediaControlFullscreenTimeRemainingDisplayElement(document));
544 }
545
546 MediaControlFullscreenTimeRemainingDisplayElement::MediaControlFullscreenTimeRemainingDisplayElement(Document* document)
547     : MediaControlTimeDisplayElement(document, MediaTimeRemainingDisplay)
548 {
549 }
550
551 const AtomicString& MediaControlFullscreenTimeRemainingDisplayElement::shadowPseudoId() const
552 {
553     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-time-remaining-display", AtomicString::ConstructFromLiteral));
554     return id;
555 }
556
557 PassRefPtr<MediaControlFullscreenCurrentTimeDisplayElement> MediaControlFullscreenCurrentTimeDisplayElement::create(Document* document)
558 {
559     return adoptRef(new MediaControlFullscreenCurrentTimeDisplayElement(document));
560 }
561
562 MediaControlFullscreenCurrentTimeDisplayElement::MediaControlFullscreenCurrentTimeDisplayElement(Document* document)
563     : MediaControlTimeDisplayElement(document, MediaCurrentTimeDisplay)
564 {
565 }
566
567 const AtomicString& MediaControlFullscreenCurrentTimeDisplayElement::shadowPseudoId() const
568 {
569     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-fullscreen-current-time-display", AtomicString::ConstructFromLiteral));
570     return id;
571 }
572
573 MediaControlAudioMuteButtonElement::MediaControlAudioMuteButtonElement(Document* document, MediaControls* controls)
574     : MediaControlMuteButtonElement(document, MediaMuteButton)
575     , m_controls(controls)
576 {
577 }
578
579 PassRefPtr<MediaControlAudioMuteButtonElement> MediaControlAudioMuteButtonElement::create(Document* document, MediaControls* controls)
580 {
581     ASSERT(controls);
582
583     RefPtr<MediaControlAudioMuteButtonElement> button = adoptRef(new MediaControlAudioMuteButtonElement(document, controls));
584     button->ensureUserAgentShadowRoot();
585     button->setType("button");
586     return button.release();
587 }
588
589 void MediaControlAudioMuteButtonElement::defaultEventHandler(Event* event)
590 {
591     if (event->type() == eventNames().mousedownEvent) {
592         // We do not mute when the media player volume/mute control is touched.
593         // Instead we show/hide the volume slider.
594         static_cast<MediaControlsBlackBerry*>(m_controls)->toggleVolumeSlider();
595         event->setDefaultHandled();
596         return;
597     }
598     if (event->type() == eventNames().mouseoverEvent)
599         m_controls->showVolumeSlider();
600
601     MediaControlMuteButtonElement::defaultEventHandler(event);
602 }
603
604 const AtomicString& MediaControlAudioMuteButtonElement::shadowPseudoId() const
605 {
606     DEFINE_STATIC_LOCAL(AtomicString, id, ("-webkit-media-controls-audio-mute-button", AtomicString::ConstructFromLiteral));
607     return id;
608 }
609
610 MediaControlsBlackBerry::MediaControlsBlackBerry(Document* document)
611     : MediaControls(document)
612     , m_buttonContainer(0)
613     , m_timeDisplayContainer(0)
614     , m_fullscreenTimeDisplayContainer(0)
615     , m_fullscreenPlayButton(0)
616     , m_fullscreenCurrentTimeDisplay(0)
617     , m_fullscreenTimeline(0)
618     , m_timeRemainingDisplay(0)
619     , m_fullscreenTimeRemainingDisplay(0)
620     , m_timelineContainer(0)
621     , m_fullscreenTimelineContainer(0)
622     , m_fullScreenDivider(0)
623     , m_fullscreenFullScreenButton(0)
624     , m_muteButton(0)
625     , m_volumeSliderContainer(0)
626     , m_embeddedPanel(0)
627     , m_fullScreenButtonContainer(0)
628     , m_playButtonContainer(0)
629     , m_placeholder(0)
630 {
631 }
632
633 PassRefPtr<MediaControls> MediaControls::create(Document* document)
634 {
635     return MediaControlsBlackBerry::createControls(document);
636 }
637
638 PassRefPtr<MediaControlsBlackBerry> MediaControlsBlackBerry::createControls(Document* document)
639 {
640     if (!document->page())
641         return 0;
642
643     RefPtr<MediaControlsBlackBerry> controls = adoptRef(new MediaControlsBlackBerry(document));
644
645     RefPtr<MediaControlPanelElement> panel = MediaControlPanelElement::create(document);
646     RefPtr<MediaControlEmbeddedPanelElement> embedPanel = MediaControlEmbeddedPanelElement::create(document);
647
648     ExceptionCode ec;
649
650     RefPtr<MediaControlPlayButtonElement> playButton = MediaControlPlayButtonElement::create(document);
651     controls->m_playButton = playButton.get();
652     embedPanel->appendChild(playButton.release(), ec, true);
653     if (ec)
654         return 0;
655
656     RefPtr<MediaControlTimelineContainerElement> timelineContainer = MediaControlTimelineContainerElement::create(document);
657
658     RefPtr<MediaControlTimelineElement> timeline = MediaControlTimelineElement::create(document, controls.get());
659     controls->m_timeline = timeline.get();
660     timelineContainer->appendChild(timeline.release(), ec, true);
661     if (ec)
662         return 0;
663
664     RefPtr<MediaControlTimeDisplayContainerElement> timeDisplayContainer = MediaControlTimeDisplayContainerElement::create(document);
665
666     RefPtr<MediaControlCurrentTimeDisplayElement> currentTimeDisplay = MediaControlCurrentTimeDisplayElement::create(document);
667     controls->m_currentTimeDisplay = currentTimeDisplay.get();
668     timeDisplayContainer->appendChild(currentTimeDisplay.release(), ec, true);
669     if (ec)
670         return 0;
671
672     RefPtr<MediaControlTimeRemainingDisplayElement> timeRemainingDisplay = MediaControlTimeRemainingDisplayElement::create(document);
673     controls->m_timeRemainingDisplay = timeRemainingDisplay.get();
674     timeDisplayContainer->appendChild(timeRemainingDisplay.release(), ec, true);
675     if (ec)
676         return 0;
677
678     controls->m_timeDisplayContainer = timeDisplayContainer.get();
679     timelineContainer->appendChild(timeDisplayContainer.release(), ec, true);
680     if (ec)
681         return 0;
682
683     controls->m_timelineContainer = timelineContainer.get();
684     embedPanel->appendChild(timelineContainer.release(), ec, true);
685     if (ec)
686         return 0;
687
688     RefPtr<MediaControlFullscreenButtonElement> fullScreenButton = MediaControlFullscreenButtonElement::create(document);
689     controls->m_fullScreenButton = fullScreenButton.get();
690     embedPanel->appendChild(fullScreenButton.release(), ec, true);
691     if (ec)
692         return 0;
693
694     if (document->page()->theme()->usesMediaControlVolumeSlider()) {
695         // The mute button and the slider element should be in the same div.
696         RefPtr<HTMLDivElement> volumeControlContainer = HTMLDivElement::create(document);
697
698         RefPtr<MediaControlVolumeSliderContainerElement> volumeSliderContainer = MediaControlVolumeSliderContainerElement::create(document);
699
700         RefPtr<MediaControlPanelVolumeSliderElement> slider = MediaControlPanelVolumeSliderElement::create(document);
701         controls->m_volumeSlider = slider.get();
702         volumeSliderContainer->appendChild(slider.release(), ec, true);
703         if (ec)
704             return 0;
705
706         controls->m_volumeSliderContainer = volumeSliderContainer.get();
707         volumeControlContainer->appendChild(volumeSliderContainer.release(), ec, true);
708         if (ec)
709             return 0;
710         RefPtr<MediaControlAudioMuteButtonElement> muteButton = MediaControlAudioMuteButtonElement::create(document, controls.get());
711         controls->m_muteButton = muteButton.get();
712         volumeControlContainer->appendChild(muteButton.release(), ec, true);
713         if (ec)
714             return 0;
715
716         embedPanel->appendChild(volumeControlContainer.release(), ec, true);
717         if (ec)
718             return 0;
719     }
720
721     RefPtr<MediaControlFullscreenTimelineContainerElement> fullscreenTimelineContainer = MediaControlFullscreenTimelineContainerElement::create(document);
722
723     RefPtr<MediaControlFullscreenTimelineElement> fullscreenTimeline = MediaControlFullscreenTimelineElement::create(document, controls.get());
724     controls->m_fullscreenTimeline = fullscreenTimeline.get();
725     fullscreenTimelineContainer->appendChild(fullscreenTimeline.release(), ec, true);
726     if (ec)
727         return 0;
728
729     RefPtr<MediaControlFullscreenTimeDisplayContainerElement> fullscreenTimeDisplayContainer = MediaControlFullscreenTimeDisplayContainerElement::create(document);
730
731     RefPtr<MediaControlFullscreenCurrentTimeDisplayElement> fullscreenCurrentTimeDisplay = MediaControlFullscreenCurrentTimeDisplayElement::create(document);
732     controls->m_fullscreenCurrentTimeDisplay = fullscreenCurrentTimeDisplay.get();
733     fullscreenTimeDisplayContainer->appendChild(fullscreenCurrentTimeDisplay.release(), ec, true);
734     if (ec)
735         return 0;
736
737     RefPtr<MediaControlFullscreenTimeRemainingDisplayElement> fullscreenTimeRemainingDisplay = MediaControlFullscreenTimeRemainingDisplayElement::create(document);
738     controls->m_fullscreenTimeRemainingDisplay = fullscreenTimeRemainingDisplay.get();
739     fullscreenTimeDisplayContainer->appendChild(fullscreenTimeRemainingDisplay.release(), ec, true);
740     if (ec)
741         return 0;
742
743     controls->m_fullscreenTimeDisplayContainer = fullscreenTimeDisplayContainer.get();
744     fullscreenTimelineContainer->appendChild(fullscreenTimeDisplayContainer.release(), ec, true);
745     if (ec)
746         return 0;
747
748     controls->m_fullscreenTimelineContainer = fullscreenTimelineContainer.get();
749     panel->appendChild(fullscreenTimelineContainer.release(), ec, true);
750     if (ec)
751         return 0;
752
753     RefPtr<MediaControlButtonGroupContainerElement> buttonGroupContainer = MediaControlButtonGroupContainerElement::create(document);
754
755     // FIXME: Only create when needed <http://webkit.org/b/57163>
756     RefPtr<MediaControlFullscreenButtonContainerElement> fullScreenButtonContainer = MediaControlFullscreenButtonContainerElement::create(document);
757     controls->m_fullScreenButtonContainer = fullScreenButtonContainer.get();
758     RefPtr<MediaControlFullscreenFullscreenButtonElement> fullscreenFullScreenButton = MediaControlFullscreenFullscreenButtonElement::create(document);
759     controls->m_fullscreenFullScreenButton = fullscreenFullScreenButton.get();
760     fullScreenButtonContainer->appendChild(fullscreenFullScreenButton.release(), ec, true);
761     if (ec)
762         return 0;
763     RefPtr<MediaControlFullscreenButtonDividerElement> fullScreenDivider = MediaControlFullscreenButtonDividerElement::create(document);
764     controls->m_fullScreenDivider = fullScreenDivider.get();
765     fullScreenButtonContainer->appendChild(fullScreenDivider.release(), ec, true);
766     if (ec)
767         return 0;
768     buttonGroupContainer->appendChild(fullScreenButtonContainer.release(), ec, true);
769     if (ec)
770         return 0;
771
772     RefPtr<MediaControlPlayButtonContainerElement> playButtonContainer = MediaControlPlayButtonContainerElement::create(document);
773     controls->m_playButtonContainer = playButtonContainer.get();
774     RefPtr<MediaControlFullscreenPlayButtonElement> fullscreenPlayButton = MediaControlFullscreenPlayButtonElement::create(document);
775     controls->m_fullscreenPlayButton = fullscreenPlayButton.get();
776     playButtonContainer->appendChild(fullscreenPlayButton.release(), ec, true);
777     if (ec)
778         return 0;
779     buttonGroupContainer->appendChild(playButtonContainer.release(), ec, true);
780     if (ec)
781         return 0;
782
783     RefPtr<MediaControlPlaceholderElement> placeholder = MediaControlPlaceholderElement::create(document);
784     controls->m_placeholder = placeholder.get();
785     buttonGroupContainer->appendChild(placeholder.release(), ec, true);
786     if (ec)
787         return 0;
788
789     controls->m_buttonContainer = buttonGroupContainer.get();
790     panel->appendChild(buttonGroupContainer.release(), ec, true);
791     if (ec)
792         return 0;
793
794     if (document->page()->theme()->supportsClosedCaptioning()) {
795         RefPtr<MediaControlToggleClosedCaptionsButtonElement> toggleClosedCaptionsButton = MediaControlToggleClosedCaptionsButtonElement::create(document, controls.get());
796         controls->m_toggleClosedCaptionsButton = toggleClosedCaptionsButton.get();
797         panel->appendChild(toggleClosedCaptionsButton.release(), ec, true);
798         if (ec)
799             return 0;
800     }
801
802     controls->m_panel = panel.get();
803     controls->appendChild(panel.release(), ec, true);
804     if (ec)
805         return 0;
806
807     controls->m_embeddedPanel = embedPanel.get();
808     controls->appendChild(embedPanel.release(), ec, true);
809     if (ec)
810         return 0;
811
812     return controls.release();
813 }
814
815 void MediaControlsBlackBerry::setMediaController(MediaControllerInterface* controller)
816 {
817     if (m_mediaController == controller)
818         return;
819
820     MediaControls::setMediaController(controller);
821
822     if (m_buttonContainer)
823         m_buttonContainer->setMediaController(controller);
824     if (m_timeDisplayContainer)
825         m_timeDisplayContainer->setMediaController(controller);
826     if (m_fullscreenTimeDisplayContainer)
827         m_fullscreenTimeDisplayContainer->setMediaController(controller);
828     if (m_fullscreenPlayButton)
829         m_fullscreenPlayButton->setMediaController(controller);
830     if (m_fullscreenCurrentTimeDisplay)
831         m_fullscreenCurrentTimeDisplay->setMediaController(controller);
832     if (m_fullscreenTimeline)
833         m_fullscreenTimeline->setMediaController(controller);
834     if (m_timeRemainingDisplay)
835         m_timeRemainingDisplay->setMediaController(controller);
836     if (m_fullscreenTimeRemainingDisplay)
837         m_fullscreenTimeRemainingDisplay->setMediaController(controller);
838     if (m_timelineContainer)
839         m_timelineContainer->setMediaController(controller);
840     if (m_fullscreenTimelineContainer)
841         m_fullscreenTimelineContainer->setMediaController(controller);
842     if (m_fullscreenFullScreenButton)
843         m_fullscreenFullScreenButton->setMediaController(controller);
844     if (m_muteButton)
845         m_muteButton->setMediaController(controller);
846     if (m_volumeSliderContainer)
847         m_volumeSliderContainer->setMediaController(controller);
848     if (m_embeddedPanel)
849         m_embeddedPanel->setMediaController(controller);
850     reset();
851 }
852
853 void MediaControlsBlackBerry::show()
854 {
855     if (m_isFullscreen) {
856         m_panel->setIsDisplayed(true);
857         m_panel->show();
858     } else {
859         m_embeddedPanel->setIsDisplayed(true);
860         m_embeddedPanel->show();
861     }
862 }
863
864 void MediaControlsBlackBerry::hide()
865 {
866     if (m_isFullscreen) {
867         m_panel->setIsDisplayed(false);
868         m_panel->hide();
869     } else {
870         m_embeddedPanel->setIsDisplayed(false);
871         m_embeddedPanel->hide();
872         m_volumeSliderContainer->hide();
873     }
874 }
875
876 void MediaControlsBlackBerry::makeOpaque()
877 {
878     if (m_isFullscreen)
879         m_panel->makeOpaque();
880     else
881         m_embeddedPanel->makeOpaque();
882 }
883
884 void MediaControlsBlackBerry::makeTransparent()
885 {
886     if (m_isFullscreen)
887         m_panel->makeTransparent();
888     else {
889         m_embeddedPanel->makeTransparent();
890         m_volumeSliderContainer->hide();
891     }
892 }
893
894 void MediaControlsBlackBerry::reset()
895 {
896     Page* page = document()->page();
897     if (!page)
898         return;
899
900     updateStatusDisplay();
901
902     if (m_fullScreenButton) {
903         if (m_mediaController->supportsFullscreen())
904             m_fullScreenButton->show();
905         else
906             m_fullScreenButton->hide();
907     }
908     if (m_fullscreenFullScreenButton) {
909         if (m_mediaController->supportsFullscreen())
910             m_fullscreenFullScreenButton->show();
911         else
912             m_fullscreenFullScreenButton->hide();
913     }
914     float duration = m_mediaController->duration();
915     if (isfinite(duration) || page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
916         float now = m_mediaController->currentTime();
917         m_timeline->setDuration(duration);
918         m_fullscreenTimeline->setDuration(duration);
919         m_timelineContainer->show();
920         m_fullscreenTimelineContainer->show();
921         m_timeline->setPosition(now);
922         m_fullscreenTimeline->setPosition(now);
923         updateCurrentTimeDisplay();
924     } else {
925         m_timelineContainer->hide();
926         m_fullscreenTimelineContainer->hide();
927     }
928
929     if (m_mediaController->hasAudio() || page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
930         m_muteButton->show();
931     else
932         m_muteButton->hide();
933
934     if (m_volumeSlider)
935         m_volumeSlider->setVolume(m_mediaController->volume());
936
937     if (m_toggleClosedCaptionsButton) {
938         if (m_mediaController->hasClosedCaptions())
939             m_toggleClosedCaptionsButton->show();
940         else
941             m_toggleClosedCaptionsButton->hide();
942     }
943
944     if (m_playButton)
945         m_playButton->updateDisplayType();
946
947     if (m_fullscreenPlayButton)
948         m_fullscreenPlayButton->updateDisplayType();
949
950     makeOpaque();
951 }
952
953 void MediaControlsBlackBerry::bufferingProgressed()
954 {
955     // We only need to update buffering progress when paused, during normal
956     // playback playbackProgressed() will take care of it.
957     if (m_mediaController->paused()) {
958         float now = m_mediaController->currentTime();
959         m_timeline->setPosition(now);
960         m_fullscreenTimeline->setPosition(now);
961     }
962 }
963
964 void MediaControlsBlackBerry::playbackStarted()
965 {
966     float now = m_mediaController->currentTime();
967     m_playButton->updateDisplayType();
968     m_fullscreenPlayButton->updateDisplayType();
969     m_timeline->setPosition(now);
970     m_fullscreenTimeline->setPosition(now);
971     updateCurrentTimeDisplay();
972
973     if (m_isFullscreen)
974         startHideFullscreenControlsTimer();
975 }
976
977 void MediaControlsBlackBerry::playbackProgressed()
978 {
979     float now = m_mediaController->currentTime();
980     m_timeline->setPosition(now);
981     m_fullscreenTimeline->setPosition(now);
982     updateCurrentTimeDisplay();
983     
984     if (!m_isMouseOverControls && m_mediaController->hasVideo())
985         makeTransparent();
986 }
987
988 void MediaControlsBlackBerry::playbackStopped()
989 {
990     float now = m_mediaController->currentTime();
991     m_playButton->updateDisplayType();
992     m_fullscreenPlayButton->updateDisplayType();
993     m_timeline->setPosition(now);
994     m_fullscreenTimeline->setPosition(now);
995     updateCurrentTimeDisplay();
996     makeOpaque();
997     
998     stopHideFullscreenControlsTimer();
999 }
1000
1001 void MediaControlsBlackBerry::updateCurrentTimeDisplay()
1002 {
1003     float now = m_mediaController->currentTime();
1004     float duration = m_mediaController->duration();
1005
1006     Page* page = document()->page();
1007     if (!page)
1008         return;
1009
1010     // Allow the theme to format the time.
1011     m_currentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION);
1012     m_currentTimeDisplay->setCurrentValue(now);
1013     m_fullscreenCurrentTimeDisplay->setInnerText(page->theme()->formatMediaControlsCurrentTime(now, duration), IGNORE_EXCEPTION);
1014     m_fullscreenCurrentTimeDisplay->setCurrentValue(now);
1015     m_timeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION);
1016     m_timeRemainingDisplay->setCurrentValue(now - duration);
1017     m_fullscreenTimeRemainingDisplay->setInnerText(page->theme()->formatMediaControlsRemainingTime(now, duration), IGNORE_EXCEPTION);
1018     m_fullscreenTimeRemainingDisplay->setCurrentValue(now - duration);
1019 }
1020
1021 void MediaControlsBlackBerry::reportedError()
1022 {
1023     Page* page = document()->page();
1024     if (!page)
1025         return;
1026
1027     if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaSliderPart)) {
1028         m_timelineContainer->hide();
1029         m_fullscreenTimelineContainer->hide();
1030     }
1031
1032     if (!page->theme()->hasOwnDisabledStateHandlingFor(MediaMuteButtonPart))
1033         m_muteButton->hide();
1034
1035     if (m_fullScreenButton)
1036         m_fullScreenButton->hide();
1037
1038     if (m_fullScreenDivider)
1039         m_fullScreenDivider->hide();
1040
1041     if (m_fullscreenFullScreenButton)
1042         m_fullscreenFullScreenButton->hide();
1043
1044     if (m_volumeSliderContainer)
1045         m_volumeSliderContainer->hide();
1046
1047     if (m_toggleClosedCaptionsButton && !page->theme()->hasOwnDisabledStateHandlingFor(MediaToggleClosedCaptionsButtonPart))
1048         m_toggleClosedCaptionsButton->hide();
1049 }
1050
1051 void MediaControlsBlackBerry::changedMute()
1052 {
1053     m_muteButton->changedMute();
1054 }
1055
1056 void MediaControlsBlackBerry::enteredFullscreen()
1057 {
1058     MediaControls::enteredFullscreen();
1059
1060     m_panel->setCanBeDragged(true);
1061     m_embeddedPanel->setCanBeDragged(true);
1062
1063     if (m_fullscreenFullScreenButton)
1064         m_fullscreenFullScreenButton->setIsFullscreen(true);
1065 }
1066
1067 void MediaControlsBlackBerry::exitedFullscreen()
1068 {
1069     m_panel->setCanBeDragged(false);
1070     m_embeddedPanel->setCanBeDragged(false);
1071
1072     if (m_fullscreenFullScreenButton)
1073         m_fullscreenFullScreenButton->setIsFullscreen(false);
1074
1075     // We will keep using the panel, but we want it to go back to the standard position.
1076     // This will matter right away because we use the panel even when not fullscreen.
1077     // And if we reenter fullscreen we also want the panel in the standard position.
1078     m_panel->resetPosition();
1079     m_embeddedPanel->resetPosition();
1080
1081     MediaControls::exitedFullscreen();
1082 }
1083
1084 void MediaControlsBlackBerry::showVolumeSlider()
1085 {
1086     if (!m_mediaController->hasAudio())
1087         return;
1088
1089     if (m_volumeSliderContainer)
1090         m_volumeSliderContainer->show();
1091 }
1092
1093 void MediaControlsBlackBerry::toggleVolumeSlider()
1094 {
1095     if (!m_mediaController->hasAudio())
1096         return;
1097
1098     if (m_volumeSliderContainer) {
1099         if (m_volumeSliderContainer->renderer() && m_volumeSliderContainer->renderer()->visibleToHitTesting())
1100             m_volumeSliderContainer->hide();
1101         else
1102             m_volumeSliderContainer->show();
1103     }
1104 }
1105
1106 bool MediaControlsBlackBerry::shouldHideControls()
1107 {
1108     if (m_isFullscreen)
1109         return !m_panel->hovered();
1110     return !m_embeddedPanel->hovered();
1111 }
1112 }
1113
1114 #endif