7f6a078d8755b41ee78c50bda42d53c830e6a999
[WebKit-https.git] / Source / WebCore / platform / graphics / blackberry / MediaPlayerPrivateBlackBerry.cpp
1 /*
2  * Copyright (C) 2011, 2012 Research In Motion Limited. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  */
18
19 #include "config.h"
20
21 #if ENABLE(VIDEO)
22 #include "MediaPlayerPrivateBlackBerry.h"
23
24 #include "CookieManager.h"
25 #include "CredentialStorage.h"
26 #include "HostWindow.h"
27 #include "MediaStreamDescriptor.h"
28 #include "MediaStreamRegistry.h"
29
30 #include <BlackBerryPlatformDeviceInfo.h>
31 #include <BlackBerryPlatformPrimitives.h>
32 #include <BlackBerryPlatformSettings.h>
33 #include <FrameLoaderClientBlackBerry.h>
34
35 #if USE(ACCELERATED_COMPOSITING)
36 #include "VideoLayerWebKitThread.h"
37 #include <BlackBerryPlatformGLES2Program.h>
38 #include <GLES2/gl2.h>
39 #endif
40
41 #include <TiledImage.h>
42
43 using namespace std;
44 using namespace BlackBerry::Platform;
45
46 namespace WebCore {
47
48 // Static callback functions for factory
49 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivate::create(MediaPlayer* player)
50 {
51     return adoptPtr(new MediaPlayerPrivate(player));
52 }
53
54 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
55 {
56     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
57 }
58
59 void MediaPlayerPrivate::getSupportedTypes(HashSet<WTF::String>& types)
60 {
61     set<BlackBerry::Platform::String> supported = PlatformPlayer::allSupportedMimeTypes();
62     set<BlackBerry::Platform::String>::iterator i = supported.begin();
63     for (; i != supported.end(); i++)
64         types.add(*i);
65 }
66
67 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const WTF::String& type, const WTF::String& codecs, const KURL& url)
68 {
69     bool isRTSP = url.protocolIs("rtsp");
70
71     if (!isRTSP && (type.isNull() || type.isEmpty())) {
72         LOG(Media, "MediaPlayer does not support type; type is null or empty.");
73         return MediaPlayer::IsNotSupported;
74     }
75
76     // spec says we should not return "probably" if the codecs string is empty
77     if (isRTSP || PlatformPlayer::mimeTypeSupported(type.ascii().data())) {
78         LOG(Media, "MediaPlayer supports type %s.", isRTSP ? "rtsp" : type.ascii().data());
79         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
80     }
81     LOG(Media, "MediaPlayer does not support type %s.", type.ascii().data());
82     return MediaPlayer::IsNotSupported;
83 }
84
85 void MediaPlayerPrivate::notifyAppActivatedEvent(bool activated)
86 {
87     PlatformPlayer::notifyAppActivatedEvent(activated);
88 }
89
90 void MediaPlayerPrivate::setCertificatePath(const WTF::String& caPath)
91 {
92     PlatformPlayer::setCertificatePath(caPath);
93 }
94
95 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
96     : m_webCorePlayer(player)
97     , m_platformPlayer(0)
98     , m_networkState(MediaPlayer::Empty)
99     , m_readyState(MediaPlayer::HaveNothing)
100     , m_fullscreenWebPageClient(0)
101 #if USE(ACCELERATED_COMPOSITING)
102     , m_bufferingTimer(this, &MediaPlayerPrivate::bufferingTimerFired)
103     , m_showBufferingImage(false)
104 #endif
105     , m_userDrivenSeekTimer(this, &MediaPlayerPrivate::userDrivenSeekTimerFired)
106     , m_lastSeekTime(0)
107     , m_lastLoadingTime(0)
108     , m_lastSeekTimePending(false)
109     , m_isAuthenticationChallenging(false)
110     , m_waitMetadataTimer(this, &MediaPlayerPrivate::waitMetadataTimerFired)
111     , m_waitMetadataPopDialogCounter(0)
112 {
113 }
114
115 MediaPlayerPrivate::~MediaPlayerPrivate()
116 {
117     if (m_isAuthenticationChallenging)
118         AuthenticationChallengeManager::instance()->cancelAuthenticationChallenge(this);
119
120     if (isFullscreen())
121         m_webCorePlayer->mediaPlayerClient()->mediaPlayerExitFullscreen();
122 #if USE(ACCELERATED_COMPOSITING)
123     // Remove media player from platform layer.
124     if (m_platformLayer)
125         static_cast<VideoLayerWebKitThread*>(m_platformLayer.get())->setMediaPlayer(0);
126 #endif
127
128     if (m_platformPlayer) {
129         if (m_platformPlayer->dialogState() == PlatformPlayer::DialogShown) {
130             m_platformPlayer->setDialogState(PlatformPlayer::MediaPlayerPrivateDestroyed);
131             m_platformPlayer->stop();
132         } else
133             deleteGuardedObject(m_platformPlayer);
134     }
135 }
136
137 void MediaPlayerPrivate::load(const WTF::String& url)
138 {
139     WTF::String modifiedUrl(url);
140
141     if (modifiedUrl.startsWith("local://")) {
142         KURL kurl = KURL(KURL(), modifiedUrl);
143         kurl.setProtocol("file");
144         WTF::String tempPath(BlackBerry::Platform::Settings::instance()->applicationLocalDirectory().c_str());
145         tempPath.append(kurl.path());
146         kurl.setPath(tempPath);
147         modifiedUrl = kurl.string();
148     }
149     if (modifiedUrl.startsWith("file://")) {
150         // The QNX Multimedia Framework cannot handle filenames containing URL escape sequences.
151         modifiedUrl = decodeURLEscapeSequences(modifiedUrl);
152     }
153
154     void* tabId = m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient();
155     int playerID = m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->playerID();
156     bool isVideo = m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsVideo();
157
158     deleteGuardedObject(m_platformPlayer);
159 #if USE(ACCELERATED_COMPOSITING)
160     m_platformPlayer = PlatformPlayer::create(this, tabId, isVideo, true, modifiedUrl.utf8().data());
161 #else
162     m_platformPlayer = PlatformPlayer::create(this, tabId, isVideo, false, modifiedUrl.utf8().data());
163 #endif
164
165     WTF::String cookiePairs;
166     if (!url.isEmpty())
167         cookiePairs = cookieManager().getCookie(KURL(ParsedURLString, url.utf8().data()), WithHttpOnlyCookies);
168     if (!cookiePairs.isEmpty() && cookiePairs.utf8().data())
169         m_platformPlayer->load(playerID, modifiedUrl.utf8().data(), m_webCorePlayer->userAgent().utf8().data(), cookiePairs.utf8().data());
170     else
171         m_platformPlayer->load(playerID, modifiedUrl.utf8().data(), m_webCorePlayer->userAgent().utf8().data(), 0);
172 }
173
174 void MediaPlayerPrivate::cancelLoad()
175 {
176     if (m_platformPlayer)
177         m_platformPlayer->cancelLoad();
178 }
179
180 void MediaPlayerPrivate::prepareToPlay()
181 {
182     if (m_platformPlayer)
183         m_platformPlayer->prepareToPlay();
184 }
185
186 void MediaPlayerPrivate::play()
187 {
188     if (m_platformPlayer) {
189         m_platformPlayer->play();
190     }
191 }
192
193 void MediaPlayerPrivate::pause()
194 {
195     if (m_platformPlayer)
196         m_platformPlayer->pause();
197 }
198
199 bool MediaPlayerPrivate::supportsFullscreen() const
200 {
201     return hasVideo();
202 }
203
204 IntSize MediaPlayerPrivate::naturalSize() const
205 {
206     if (!m_platformPlayer)
207         return IntSize();
208
209     // Cannot return empty size, otherwise paint() will never get called.
210     // Also, the values here will affect the aspect ratio of the output rectangle that will
211     // be used for renderering the video, so we must take PAR into account.
212     // Now, hope that metadata has been provided before this gets called if this is a video.
213     double pixelWidth = static_cast<double>(m_platformPlayer->pixelWidth());
214     double pixelHeight = static_cast<double>(m_platformPlayer->pixelHeight());
215     if (!m_platformPlayer->pixelWidth() || !m_platformPlayer->pixelHeight())
216         pixelWidth = pixelHeight = 1.0;
217
218     // Use floating point arithmetic to eliminate the chance of integer
219     // overflow. PAR numbers can be 5 digits or more.
220     double adjustedSourceWidth = static_cast<double>(m_platformPlayer->sourceWidth()) * pixelWidth / pixelHeight;
221     return IntSize(static_cast<int>(adjustedSourceWidth + 0.5), m_platformPlayer->sourceHeight());
222 }
223
224 bool MediaPlayerPrivate::hasVideo() const
225 {
226     if (m_platformPlayer)
227         return m_platformPlayer->hasVideo();
228     return false;
229 }
230
231 bool MediaPlayerPrivate::hasAudio() const
232 {
233     if (m_platformPlayer)
234         return m_platformPlayer->hasAudio();
235     return false;
236 }
237
238 void MediaPlayerPrivate::setVisible(bool)
239 {
240     notImplemented();
241 }
242
243 float MediaPlayerPrivate::duration() const
244 {
245     if (m_platformPlayer)
246         return m_platformPlayer->duration();
247     return 0.0f;
248 }
249
250 static const double SeekSubmissionDelay = 0.1; // Reasonable throttling value.
251 static const double ShortMediaThreshold = SeekSubmissionDelay * 2.0;
252
253 float MediaPlayerPrivate::currentTime() const
254 {
255     if (!m_platformPlayer)
256         return 0.0f;
257
258     // For very short media on the order of SeekSubmissionDelay we get
259     // unwanted repeats if we don't return the most up-to-date currentTime().
260     bool shortMedia = m_platformPlayer->duration() < ShortMediaThreshold;
261     return m_userDrivenSeekTimer.isActive() && !shortMedia ? m_lastSeekTime: m_platformPlayer->currentTime();
262 }
263
264 void MediaPlayerPrivate::seek(float time)
265 {
266     if (!m_platformPlayer)
267         return;
268
269     m_lastSeekTime = time;
270     m_lastSeekTimePending = true;
271     if (!m_userDrivenSeekTimer.isActive())
272         userDrivenSeekTimerFired(0);
273 }
274
275 void MediaPlayerPrivate::userDrivenSeekTimerFired(Timer<MediaPlayerPrivate>*)
276 {
277     if (m_lastSeekTimePending) {
278         m_platformPlayer->seek(m_lastSeekTime);
279         m_lastSeekTimePending = false;
280         m_userDrivenSeekTimer.startOneShot(SeekSubmissionDelay);
281     }
282 }
283
284 bool MediaPlayerPrivate::seeking() const
285 {
286     return false;
287 }
288
289 void MediaPlayerPrivate::setRate(float rate)
290 {
291     if (m_platformPlayer)
292         m_platformPlayer->setRate(rate);
293 }
294
295 bool MediaPlayerPrivate::paused() const
296 {
297     if (m_platformPlayer)
298         return m_platformPlayer->paused();
299     return false;
300 }
301
302 void MediaPlayerPrivate::setVolume(float volume)
303 {
304     if (m_platformPlayer)
305         m_platformPlayer->setVolume(volume);
306 }
307
308 void MediaPlayerPrivate::setMuted(bool muted)
309 {
310     if (m_platformPlayer)
311         m_platformPlayer->setMuted(muted);
312 }
313
314 bool MediaPlayerPrivate::muted() const
315 {
316     if (m_platformPlayer)
317         return m_platformPlayer->muted();
318     return false;
319 }
320
321 MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
322 {
323     return m_networkState;
324 }
325
326 MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
327 {
328     return m_readyState;
329 }
330
331 float MediaPlayerPrivate::maxTimeSeekable() const
332 {
333     if (m_platformPlayer)
334         return m_platformPlayer->maxTimeSeekable();
335     return 0.0f;
336 }
337
338 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
339 {
340     if (!m_platformPlayer)
341         return TimeRanges::create();
342
343     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
344     if (float bufferLoaded = m_platformPlayer->bufferLoaded())
345         timeRanges->add(0, bufferLoaded);
346     return timeRanges.release();
347 }
348
349 bool MediaPlayerPrivate::didLoadingProgress() const
350 {
351     if (!m_platformPlayer)
352         return false;
353
354     float bufferLoaded = m_platformPlayer->bufferLoaded();
355     if (bufferLoaded == m_lastLoadingTime)
356         return false;
357
358     m_lastLoadingTime = bufferLoaded;
359     return true;
360 }
361
362 void MediaPlayerPrivate::setSize(const IntSize&)
363 {
364     notImplemented();
365 }
366
367 void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
368 {
369     if (!m_platformPlayer)
370         return;
371
372 #if USE(ACCELERATED_COMPOSITING)
373     if (supportsAcceleratedRendering()) {
374         // Only process paint calls coming via the accelerated compositing code
375         // path, where we get called with a null graphics context. See
376         // LayerCompositingThread::drawTextures(). Ignore calls from the regular
377         // rendering path.
378         if (!context)
379             m_platformPlayer->notifyOutputUpdate(BlackBerry::Platform::IntRect(rect.x(), rect.y(), rect.width(), rect.height()));
380
381         return;
382     }
383 #endif
384
385     paintCurrentFrameInContext(context, rect);
386 }
387
388 void MediaPlayerPrivate::paintCurrentFrameInContext(GraphicsContext* context, const IntRect& rect)
389 {
390     if (!hasVideo() || context->paintingDisabled() || !m_webCorePlayer->visible())
391         return;
392
393     BlackBerry::Platform::Graphics::Drawable* dst = context->platformContext();
394
395     BlackBerry::Platform::IntRect platformRect(rect.x(), rect.y(), rect.width(), rect.height());
396     IntRect clippedRect = m_webCorePlayer->mediaPlayerClient()->mediaPlayerWindowClipRect();
397     BlackBerry::Platform::IntRect platformWindowClipRect(clippedRect.x(), clippedRect.y(), clippedRect.width(), clippedRect.height());
398     m_platformPlayer->paint(dst, platformRect, platformWindowClipRect);
399 }
400
401 bool MediaPlayerPrivate::hasAvailableVideoFrame() const
402 {
403     if (m_platformPlayer)
404         return m_platformPlayer->hasAvailableVideoFrame();
405     return false;
406 }
407
408 bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
409 {
410     return true;
411 }
412
413 MediaPlayer::MovieLoadType MediaPlayerPrivate::movieLoadType() const
414 {
415     if (m_platformPlayer)
416         return static_cast<MediaPlayer::MovieLoadType>(m_platformPlayer->movieLoadType());
417     return MediaPlayer::Unknown;
418 }
419
420 void MediaPlayerPrivate::prepareForRendering()
421 {
422     if (m_platformPlayer)
423         m_platformPlayer->prepareForRendering();
424 }
425
426 void MediaPlayerPrivate::resizeSourceDimensions()
427 {
428     if (!m_webCorePlayer)
429         return;
430
431     if (!m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsVideo())
432         return;
433
434     // If we don't know what the width and height of the video source is, then we need to set it to something sane.
435     if (m_platformPlayer->sourceWidth() && m_platformPlayer->sourceHeight())
436         return;
437
438     LayoutRect rect = m_webCorePlayer->mediaPlayerClient()->mediaPlayerContentBoxRect();
439     m_platformPlayer->setSourceDimension(rect.width().toUnsigned(), rect.height().toUnsigned());
440 }
441
442 void MediaPlayerPrivate::setFullscreenWebPageClient(BlackBerry::WebKit::WebPageClient* client)
443 {
444     if (m_fullscreenWebPageClient == client)
445         return;
446
447     m_fullscreenWebPageClient = client;
448     m_platformPlayer->toggleFullscreen(client);
449
450     // The following repaint is needed especially if video is paused and
451     // fullscreen is exiting, so that a MediaPlayerPrivate::paint() is
452     // triggered and the code in outputUpdate() sets the correct window
453     // rectangle.
454     if (!client)
455         m_webCorePlayer->repaint();
456 }
457
458 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getWindow()
459 {
460     return m_platformPlayer->getWindow();
461 }
462
463 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getPeerWindow(const char* uniqueID) const
464 {
465     return m_platformPlayer->getPeerWindow(uniqueID);
466 }
467
468 BlackBerry::Platform::IntRect MediaPlayerPrivate::getWindowScreenRect() const
469 {
470     unsigned x, y, width, height;
471     m_platformPlayer->getWindowPosition(x, y, width, height);
472     return BlackBerry::Platform::IntRect(x, y, width, height);
473 }
474
475 const char* MediaPlayerPrivate::mmrContextName()
476 {
477     return m_platformPlayer->mmrContextName();
478 }
479
480 float MediaPlayerPrivate::percentLoaded()
481 {
482     if (!m_platformPlayer->duration())
483         return 0;
484
485     float buffered = 0;
486     RefPtr<TimeRanges> timeRanges = this->buffered();
487     for (unsigned i = 0; i < timeRanges->length(); ++i) {
488         ExceptionCode ignoredException;
489         float start = timeRanges->start(i, ignoredException);
490         float end = timeRanges->end(i, ignoredException);
491         buffered += end - start;
492     }
493
494     float loaded = buffered / m_platformPlayer->duration();
495     return loaded;
496 }
497
498 unsigned MediaPlayerPrivate::sourceWidth()
499 {
500     return m_platformPlayer->sourceWidth();
501 }
502
503 unsigned MediaPlayerPrivate::sourceHeight()
504 {
505     return m_platformPlayer->sourceHeight();
506 }
507
508 void MediaPlayerPrivate::setAllowPPSVolumeUpdates(bool allow)
509 {
510     if (m_platformPlayer)
511         return m_platformPlayer->setAllowPPSVolumeUpdates(allow);
512 }
513
514 void MediaPlayerPrivate::updateStates()
515 {
516     MediaPlayer::NetworkState oldNetworkState = m_networkState;
517     MediaPlayer::ReadyState oldReadyState = m_readyState;
518
519     PlatformPlayer::Error currentError = m_platformPlayer->error();
520
521     if (currentError != PlatformPlayer::MediaOK) {
522         m_readyState = MediaPlayer::HaveNothing;
523         if (currentError == PlatformPlayer::MediaDecodeError)
524             m_networkState = MediaPlayer::DecodeError;
525         else if (currentError == PlatformPlayer::MediaMetaDataError
526             || currentError == PlatformPlayer::MediaAudioReceiveError
527             || currentError == PlatformPlayer::MediaVideoReceiveError)
528             m_networkState = MediaPlayer::NetworkError;
529     } else {
530         switch (m_platformPlayer->mediaState()) {
531         case PlatformPlayer::MMRPlayStateIdle:
532             m_networkState = MediaPlayer::Idle;
533             break;
534         case PlatformPlayer::MMRPlayStatePlaying:
535             m_networkState = MediaPlayer::Loading;
536             break;
537         case PlatformPlayer::MMRPlayStateStopped:
538             m_networkState = MediaPlayer::Idle;
539             break;
540         case PlatformPlayer::MMRPlayStateUnknown:
541         default:
542             break;
543         }
544
545         switch (m_platformPlayer->state()) {
546         case PlatformPlayer::MP_STATE_IDLE:
547             if (isFullscreen())
548                 m_webCorePlayer->mediaPlayerClient()->mediaPlayerExitFullscreen();
549             break;
550         case PlatformPlayer::MP_STATE_ACTIVE:
551             break;
552         case PlatformPlayer::MP_STATE_UNSUPPORTED:
553             break;
554         default:
555             break;
556         }
557         if ((duration() || movieLoadType() == MediaPlayer::LiveStream)
558             && m_readyState != MediaPlayer::HaveEnoughData)
559             m_readyState = MediaPlayer::HaveEnoughData;
560     }
561
562     if (m_readyState != oldReadyState)
563         m_webCorePlayer->readyStateChanged();
564     if (m_networkState != oldNetworkState)
565         m_webCorePlayer->networkStateChanged();
566 }
567
568 // IPlatformPlayerListener callbacks implementation
569 void MediaPlayerPrivate::onStateChanged(PlatformPlayer::MpState)
570 {
571     updateStates();
572 }
573
574 void MediaPlayerPrivate::onMediaStatusChanged(PlatformPlayer::MMRPlayState)
575 {
576     updateStates();
577 }
578
579 void MediaPlayerPrivate::onError(PlatformPlayer::Error type)
580 {
581     updateStates();
582 }
583
584 void MediaPlayerPrivate::onDurationChanged(float duration)
585 {
586     updateStates();
587     m_webCorePlayer->durationChanged();
588 }
589
590 void MediaPlayerPrivate::onTimeChanged(float)
591 {
592     m_webCorePlayer->timeChanged();
593 }
594
595 void MediaPlayerPrivate::onPauseStateChanged()
596 {
597     if (!isFullscreen())
598         return;
599
600     // Paused state change not due to local controller.
601     if (m_platformPlayer->isPaused())
602         m_webCorePlayer->mediaPlayerClient()->mediaPlayerPause();
603     else {
604         // The HMI fullscreen widget has resumed play. Check if the
605         // pause timeout occurred.
606         m_platformPlayer->processPauseTimeoutIfNecessary();
607         m_webCorePlayer->mediaPlayerClient()->mediaPlayerPlay();
608     }
609 }
610
611 void MediaPlayerPrivate::onRateChanged(float)
612 {
613     m_webCorePlayer->rateChanged();
614 }
615
616 void MediaPlayerPrivate::onVolumeChanged(float volume)
617 {
618     m_webCorePlayer->volumeChanged(volume);
619 }
620
621 void MediaPlayerPrivate::onRepaint()
622 {
623     m_webCorePlayer->repaint();
624 }
625
626 void MediaPlayerPrivate::onSizeChanged()
627 {
628     resizeSourceDimensions();
629     if (hasVideo())
630         m_webCorePlayer->sizeChanged();
631 }
632
633 void MediaPlayerPrivate::onPlayNotified()
634 {
635     m_webCorePlayer->mediaPlayerClient()->mediaPlayerPlay();
636 }
637
638 void MediaPlayerPrivate::onPauseNotified()
639 {
640     m_webCorePlayer->mediaPlayerClient()->mediaPlayerPause();
641 }
642
643 static const int popupDialogInterval = 10;
644 static const double checkMetadataReadyInterval = 0.5;
645 void MediaPlayerPrivate::onWaitMetadataNotified(bool hasFinished, int timeWaited)
646 {
647     if (!hasFinished) {
648         if (!m_waitMetadataTimer.isActive()) {
649             // Make sure to popup dialog every 10 seconds after metadata start to load.
650             // This should be set only once at the first time when user press the play button.
651             m_waitMetadataPopDialogCounter = static_cast<int>(timeWaited / checkMetadataReadyInterval);
652             m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
653         }
654     } else if (m_waitMetadataTimer.isActive()) {
655         m_waitMetadataTimer.stop();
656         m_waitMetadataPopDialogCounter = 0;
657     }
658 }
659
660 void MediaPlayerPrivate::waitMetadataTimerFired(Timer<MediaPlayerPrivate>*)
661 {
662     if (m_platformPlayer->isMetadataReady()) {
663         m_waitMetadataPopDialogCounter = 0;
664         m_platformPlayer->playWithMetadataReady();
665         return;
666     }
667
668     static const int hitTimeToPopupDialog = static_cast<int>(popupDialogInterval / checkMetadataReadyInterval);
669     m_waitMetadataPopDialogCounter++;
670     if (m_waitMetadataPopDialogCounter < hitTimeToPopupDialog) {
671         m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
672         return;
673     }
674     m_waitMetadataPopDialogCounter = 0;
675
676     PlatformPlayer::DialogResult wait = m_platformPlayer->showErrorDialog(PlatformPlayer::MediaMetaDataTimeoutError);
677     if (wait == PlatformPlayer::DialogEmergencyExit)
678         return;
679     if (wait == PlatformPlayer::DialogResponse0)
680         onPauseNotified();
681     else {
682         if (m_platformPlayer->isMetadataReady()) {
683             m_platformPlayer->playWithMetadataReady();
684         } else
685             m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
686     }
687 }
688
689 #if USE(ACCELERATED_COMPOSITING)
690 void MediaPlayerPrivate::onBuffering(bool flag)
691 {
692     setBuffering(flag);
693 }
694 #endif
695
696 static ProtectionSpace generateProtectionSpaceFromMMRAuthChallenge(const MMRAuthChallenge& authChallenge)
697 {
698     KURL url(ParsedURLString, WTF::String(authChallenge.url().c_str()));
699     ASSERT(url.isValid());
700
701     return ProtectionSpace(url.host(), url.port(),
702         static_cast<ProtectionSpaceServerType>(authChallenge.serverType()),
703         authChallenge.realm().c_str(),
704         static_cast<ProtectionSpaceAuthenticationScheme>(authChallenge.authScheme()));
705 }
706
707 void MediaPlayerPrivate::onAuthenticationNeeded(MMRAuthChallenge& authChallenge)
708 {
709     KURL url(ParsedURLString, WTF::String(authChallenge.url().c_str()));
710     if (!url.isValid())
711         return;
712
713     ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
714     Credential credential = CredentialStorage::get(protectionSpace);
715     if (!credential.isEmpty()) {
716         notifyChallengeResult(url, protectionSpace, AuthenticationChallengeSuccess, credential);
717         return;
718     }
719
720     m_isAuthenticationChallenging = true;
721     AuthenticationChallengeManager::instance()->authenticationChallenge(url, protectionSpace, credential,
722         this, m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient());
723 }
724
725 void MediaPlayerPrivate::notifyChallengeResult(const KURL& url, const ProtectionSpace& protectionSpace, AuthenticationChallengeResult result, const Credential& credential)
726 {
727     m_isAuthenticationChallenging = false;
728
729     if (result != AuthenticationChallengeSuccess || !url.isValid())
730         return;
731
732     m_platformPlayer->reloadWithCredential(credential.user().utf8(WTF::String::StrictConversion).data(),
733         credential.password().utf8(WTF::String::StrictConversion).data(),
734         static_cast<MMRAuthChallenge::CredentialPersistence>(credential.persistence()));
735 }
736
737 void MediaPlayerPrivate::onAuthenticationAccepted(const MMRAuthChallenge& authChallenge) const
738 {
739     KURL url(ParsedURLString, WTF::String(authChallenge.url().c_str()));
740     if (!url.isValid())
741         return;
742
743     ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
744     Credential savedCredential = CredentialStorage::get(protectionSpace);
745     if (savedCredential.isEmpty())
746         CredentialStorage::set(Credential(authChallenge.username().c_str(), authChallenge.password().c_str(), static_cast<CredentialPersistence>(authChallenge.persistence())), protectionSpace, url);
747 }
748
749 int MediaPlayerPrivate::onShowErrorDialog(PlatformPlayer::Error type)
750 {
751     using namespace BlackBerry::WebKit;
752
753     WebPageClient::AlertType atype;
754     switch (type) {
755     case PlatformPlayer::MediaOK:
756         atype = WebPageClient::MediaOK;
757         break;
758     case PlatformPlayer::MediaDecodeError:
759         atype = WebPageClient::MediaDecodeError;
760         break;
761     case PlatformPlayer::MediaMetaDataError:
762         atype = WebPageClient::MediaMetaDataError;
763         break;
764     case PlatformPlayer::MediaMetaDataTimeoutError:
765         atype = WebPageClient::MediaMetaDataTimeoutError;
766         break;
767     case PlatformPlayer::MediaNoMetaDataError:
768         atype = WebPageClient::MediaNoMetaDataError;
769         break;
770     case PlatformPlayer::MediaVideoReceiveError:
771         atype = WebPageClient::MediaVideoReceiveError;
772         break;
773     case PlatformPlayer::MediaAudioReceiveError:
774         atype = WebPageClient::MediaAudioReceiveError;
775         break;
776     case PlatformPlayer::MediaInvalidError:
777         atype = WebPageClient::MediaInvalidError;
778         break;
779     default:
780         LOG(Media, "Alert type does not exist.");
781         return -1;
782     }
783     return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->showAlertDialog(atype);
784 }
785
786 static WebMediaStreamSource toWebMediaStreamSource(MediaStreamSource* src)
787 {
788     return WebMediaStreamSource(src->id().utf8().data(), static_cast<WebMediaStreamSource::Type>(src->type()), src->name().utf8().data());
789 }
790
791 static WebMediaStreamDescriptor toWebMediaStreamDescriptor(MediaStreamDescriptor* d)
792 {
793     vector<WebMediaStreamSource> audioSources;
794     for (size_t i = 0; i < d->numberOfAudioComponents(); i++)
795         audioSources.push_back(toWebMediaStreamSource(d->audioComponent(i)->source()));
796
797     vector<WebMediaStreamSource> videoSources;
798     for (size_t i = 0; i < d->numberOfVideoComponents(); i++)
799         videoSources.push_back(toWebMediaStreamSource(d->videoComponent(i)->source()));
800
801     return WebMediaStreamDescriptor(d->label().utf8().data(), audioSources, videoSources);
802 }
803
804 WebMediaStreamDescriptor MediaPlayerPrivate::lookupMediaStream(const BlackBerry::Platform::String& url)
805 {
806     MediaStreamDescriptor* descriptor = MediaStreamRegistry::registry().lookupMediaStreamDescriptor(WTF::String::fromUTF8(url.c_str()));
807     if (!descriptor)
808         return WebMediaStreamDescriptor();
809
810     return toWebMediaStreamDescriptor(descriptor);
811 }
812
813 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::platformWindow()
814 {
815     return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->platformWindow();
816 }
817
818 bool MediaPlayerPrivate::isProcessingUserGesture() const
819 {
820     return m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsProcessingUserGesture();
821 }
822
823 bool MediaPlayerPrivate::isFullscreen() const
824 {
825     return m_fullscreenWebPageClient;
826 }
827
828 bool MediaPlayerPrivate::isElementPaused() const
829 {
830     return m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsPaused();
831 }
832
833 bool MediaPlayerPrivate::isTabVisible() const
834 {
835     return m_webCorePlayer->mediaPlayerClient()->mediaPlayerHostWindow()->platformPageClient()->isVisible();
836 }
837
838 bool MediaPlayerPrivate::supportsAcceleratedRendering() const
839 {
840     if (m_platformPlayer)
841         return m_platformPlayer->supportsAcceleratedRendering();
842     return false;
843 }
844
845 #if USE(ACCELERATED_COMPOSITING)
846 static const double BufferingAnimationDelay = 1.0 / 24;
847 static unsigned* s_bufferingImageData = 0;
848 static int s_bufferingImageWidth = 0;
849 static int s_bufferingImageHeight = 0;
850
851 PlatformMedia MediaPlayerPrivate::platformMedia() const
852 {
853     PlatformMedia pm;
854     pm.type = PlatformMedia::QNXMediaPlayerType;
855     pm.media.qnxMediaPlayer = const_cast<MediaPlayerPrivate*>(this);
856     return pm;
857 }
858
859 PlatformLayer* MediaPlayerPrivate::platformLayer() const
860 {
861     if (m_platformLayer)
862         return m_platformLayer.get();
863     return 0;
864 }
865
866 static void loadBufferingImageData()
867 {
868     static bool loaded = false;
869     if (!loaded) {
870         static Image* bufferingIcon = Image::loadPlatformResource("vidbuffer").leakRef();
871
872         NativeImagePtr nativeImage = bufferingIcon->nativeImageForCurrentFrame();
873         if (!nativeImage)
874             return;
875
876         loaded = true;
877         s_bufferingImageWidth = bufferingIcon->width();
878         s_bufferingImageHeight = bufferingIcon->height();
879         int bufSize = bufferingIcon->decodedSize();
880         s_bufferingImageData = static_cast<unsigned*>(malloc(bufSize));
881
882         nativeImage->readPixels(s_bufferingImageData, s_bufferingImageWidth * s_bufferingImageHeight);
883
884         bufferingIcon->deref();
885     }
886 }
887
888 void MediaPlayerPrivate::bufferingTimerFired(Timer<MediaPlayerPrivate>*)
889 {
890     if (m_showBufferingImage) {
891         if (!isFullscreen() && m_platformLayer)
892             m_platformLayer->setNeedsDisplay();
893         m_bufferingTimer.startOneShot(BufferingAnimationDelay);
894     }
895 }
896
897 void MediaPlayerPrivate::setBuffering(bool buffering)
898 {
899     if (!m_webCorePlayer || !m_webCorePlayer->mediaPlayerClient() || !m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsVideo())
900         buffering = false; // Buffering animation not visible for audio.
901
902     if (buffering != m_showBufferingImage) {
903         m_showBufferingImage = buffering;
904         if (buffering) {
905             loadBufferingImageData();
906             m_bufferingTimer.startOneShot(BufferingAnimationDelay);
907         } else
908             m_bufferingTimer.stop();
909
910         if (m_platformLayer)
911             m_platformLayer->setNeedsDisplay();
912     }
913 }
914
915 static unsigned allocateTextureId()
916 {
917     unsigned texid;
918     glGenTextures(1, &texid);
919     glBindTexture(GL_TEXTURE_2D, texid);
920     // Do basic linear filtering on resize.
921     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
922     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
923     // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE.
924     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
925     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
926     return texid;
927 }
928
929 void MediaPlayerPrivate::drawBufferingAnimation(const TransformationMatrix& matrix, const Graphics::GLES2Program& program)
930 {
931     if (m_showBufferingImage && s_bufferingImageData && !isFullscreen()) {
932         TransformationMatrix renderMatrix = matrix;
933
934         // Rotate the buffering indicator so that it takes 1 second to do 1 revolution.
935         timespec time;
936         clock_gettime(CLOCK_REALTIME, &time);
937         renderMatrix.rotate(time.tv_nsec / 1000000000.0 * 360.0);
938
939         static bool initialized = false;
940         static unsigned texId = allocateTextureId();
941         glBindTexture(GL_TEXTURE_2D, texId);
942         if (!initialized) {
943             initialized = true;
944             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s_bufferingImageWidth, s_bufferingImageHeight,
945                 0, GL_RGBA, GL_UNSIGNED_BYTE, s_bufferingImageData);
946             free(s_bufferingImageData);
947         }
948
949         float texcoords[] = { 0, 0,  0, 1,  1, 1,  1, 0 };
950         FloatPoint vertices[4];
951         float bx = s_bufferingImageWidth / 2.0;
952         float by = s_bufferingImageHeight / 2.0;
953         vertices[0] = renderMatrix.mapPoint(FloatPoint(-bx, -by));
954         vertices[1] = renderMatrix.mapPoint(FloatPoint(-bx, by));
955         vertices[2] = renderMatrix.mapPoint(FloatPoint(bx, by));
956         vertices[3] = renderMatrix.mapPoint(FloatPoint(bx, -by));
957
958         glEnable(GL_BLEND);
959         glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
960         glUniform1f(program.opacityLocation(), 1.0);
961         glVertexAttribPointer(program.positionLocation(), 2, GL_FLOAT, GL_FALSE, 0, vertices);
962         glVertexAttribPointer(program.texCoordLocation(), 2, GL_FLOAT, GL_FALSE, 0, texcoords);
963         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
964     }
965 }
966 #endif
967
968 void MediaPlayerPrivate::onConditionallyEnterFullscreen()
969 {
970     Document* owningDocument = m_webCorePlayer->mediaPlayerClient()->mediaPlayerOwningDocument();
971     BlackBerry::Platform::DeviceInfo* info = BlackBerry::Platform::DeviceInfo::instance();
972
973     // Don't allow video in <embed> and <object> containers to go fullscreen
974     // on play because this does not currently work. Detect this by checking
975     // for MediaDocument with a parent document.
976     if (owningDocument->isMediaDocument() && owningDocument->parentDocument())
977         return;
978
979     if (info->isMobile()) {
980         // This is a mobile device (small screen), not a tablet, so we
981         // enter fullscreen video on user-initiated plays.
982         bool nothingIsFullscreen = !m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsFullscreen();
983 #if ENABLE(FULLSCREEN_API)
984         if (owningDocument->webkitIsFullScreen())
985             nothingIsFullscreen = false;
986 #endif
987         if (nothingIsFullscreen)
988             m_webCorePlayer->mediaPlayerClient()->mediaPlayerEnterFullscreen();
989     }
990 }
991
992 void MediaPlayerPrivate::onExitFullscreen()
993 {
994     if (m_webCorePlayer->mediaPlayerClient()->mediaPlayerIsFullscreen())
995         m_webCorePlayer->mediaPlayerClient()->mediaPlayerExitFullscreen();
996 }
997
998 void MediaPlayerPrivate::onCreateHolePunchRect()
999 {
1000 #if USE(ACCELERATED_COMPOSITING)
1001     // Create platform layer for video (create hole punch rect).
1002     if (!m_platformLayer && supportsAcceleratedRendering()) {
1003         m_showBufferingImage = false;
1004         m_platformLayer = VideoLayerWebKitThread::create(m_webCorePlayer);
1005     }
1006 #endif
1007 }
1008
1009 void MediaPlayerPrivate::onDestroyHolePunchRect()
1010 {
1011 #if USE(ACCELERATED_COMPOSITING)
1012     setBuffering(false);
1013     // Remove media player from platform layer (remove hole punch rect).
1014     if (m_platformLayer) {
1015         static_cast<VideoLayerWebKitThread*>(m_platformLayer.get())->setMediaPlayer(0);
1016         m_platformLayer.clear();
1017     }
1018 #endif
1019 }
1020
1021 } // namespace WebCore
1022
1023 #endif // ENABLE(VIDEO)