[BlackBerry] Loading media data with http authentication
[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 "Credential.h"
26 #include "CredentialStorage.h"
27 #include "Frame.h"
28 #include "FrameView.h"
29 #include "GraphicsContext.h"
30 #include "HTMLMediaElement.h"
31 #include "HTMLNames.h"
32 #include "HostWindow.h"
33 #include "NotImplemented.h"
34 #include "PlatformContextSkia.h"
35 #include "ProtectionSpace.h"
36 #include "RenderBox.h"
37 #include "TimeRanges.h"
38 #include "WebPageClient.h"
39
40 #include <BlackBerryPlatformClient.h>
41 #include <set>
42 #include <string>
43 #include <wtf/text/CString.h>
44
45 #if USE(ACCELERATED_COMPOSITING)
46 #include "NativeImageSkia.h"
47 #include "VideoLayerWebKitThread.h"
48 #include <GLES2/gl2.h>
49 #endif
50
51 using namespace std;
52 using namespace BlackBerry::Platform;
53
54 namespace WebCore {
55
56 // Static callback functions for factory
57 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivate::create(MediaPlayer* player)
58 {
59     return adoptPtr(new MediaPlayerPrivate(player));
60 }
61
62 void MediaPlayerPrivate::registerMediaEngine(MediaEngineRegistrar registrar)
63 {
64     registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
65 }
66
67 void MediaPlayerPrivate::getSupportedTypes(HashSet<String>& types)
68 {
69     set<string> supported = MMRPlayer::allSupportedMimeTypes();
70     set<string>::iterator i = supported.begin();
71     for (; i != supported.end(); i++)
72         types.add(i->c_str());
73 }
74
75 MediaPlayer::SupportsType MediaPlayerPrivate::supportsType(const String& type, const String& codecs)
76 {
77     if (type.isNull() || type.isEmpty()) {
78         LOG(Media, "MediaPlayer does not support type; type is null or empty.");
79         return MediaPlayer::IsNotSupported;
80     }
81
82     // spec says we should not return "probably" if the codecs string is empty
83     if (MMRPlayer::mimeTypeSupported(type.ascii().data())) {
84         LOG(Media, "MediaPlayer supports type; cache contains type '%s'.", type.ascii().data());
85         return codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported;
86     }
87     LOG(Media, "MediaPlayer does not support type; cache doesn't contain type '%s'.", type.ascii().data());
88     return MediaPlayer::IsNotSupported;
89 }
90
91 void MediaPlayerPrivate::notifyAppActivatedEvent(bool activated)
92 {
93     MMRPlayer::notifyAppActivatedEvent(activated);
94 }
95
96 void MediaPlayerPrivate::setCertificatePath(const String& caPath)
97 {
98     MMRPlayer::setCertificatePath(string(caPath.utf8().data()));
99 }
100
101 MediaPlayerPrivate::MediaPlayerPrivate(MediaPlayer* player)
102     : m_webCorePlayer(player)
103     , m_networkState(MediaPlayer::Empty)
104     , m_readyState(MediaPlayer::HaveNothing)
105     , m_fullscreenWebPageClient(0)
106 #if USE(ACCELERATED_COMPOSITING)
107     , m_bufferingTimer(this, &MediaPlayerPrivate::bufferingTimerFired)
108     , m_showBufferingImage(false)
109     , m_mediaIsBuffering(false)
110 #endif
111     , m_userDrivenSeekTimer(this, &MediaPlayerPrivate::userDrivenSeekTimerFired)
112     , m_lastSeekTime(0)
113     , m_waitMetadataTimer(this, &MediaPlayerPrivate::waitMetadataTimerFired)
114     , m_waitMetadataPopDialogCounter(0)
115 {
116     void* tabId = 0;
117     if (frameView() && frameView()->hostWindow())
118         tabId = frameView()->hostWindow()->platformPageClient();
119 #if USE(ACCELERATED_COMPOSITING)
120     m_platformPlayer = new MMRPlayer(this, tabId, true);
121 #else
122     m_platformPlayer = new MMRPlayer(this, tabId, false);
123 #endif
124 }
125
126 MediaPlayerPrivate::~MediaPlayerPrivate()
127 {
128     if (isFullscreen()) {
129         HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
130         element->exitFullscreen();
131     }
132 #if USE(ACCELERATED_COMPOSITING)
133     // Remove media player from platform layer.
134     if (m_platformLayer)
135         static_cast<VideoLayerWebKitThread*>(m_platformLayer.get())->setMediaPlayer(0);
136 #endif
137
138     deleteGuardedObject(m_platformPlayer);
139 }
140
141 void MediaPlayerPrivate::load(const String& url)
142 {
143     String modifiedUrl(url);
144
145     if (modifiedUrl.startsWith("local://")) {
146         KURL kurl = KURL(KURL(), modifiedUrl);
147         kurl.setProtocol("file");
148         String tempPath(BlackBerry::Platform::Client::get()->getApplicationLocalDirectory().c_str());
149         tempPath.append(kurl.path());
150         kurl.setPath(tempPath);
151         modifiedUrl = kurl.string();
152     }
153     if (modifiedUrl.startsWith("file://")) {
154         // The QNX Multimedia Framework cannot handle filenames containing URL escape sequences.
155         modifiedUrl = decodeURLEscapeSequences(modifiedUrl);
156     }
157
158     String cookiePairs;
159     if (!url.isEmpty())
160         cookiePairs = cookieManager().getCookie(KURL(ParsedURLString, url.utf8().data()), WithHttpOnlyCookies);
161     if (!cookiePairs.isEmpty() && cookiePairs.utf8().data())
162         m_platformPlayer->load(modifiedUrl.utf8().data(), userAgent(modifiedUrl).utf8().data(), cookiePairs.utf8().data());
163     else
164         m_platformPlayer->load(modifiedUrl.utf8().data(), userAgent(modifiedUrl).utf8().data(), 0);
165 }
166
167 void MediaPlayerPrivate::cancelLoad()
168 {
169     m_platformPlayer->cancelLoad();
170 }
171
172 void MediaPlayerPrivate::prepareToPlay()
173 {
174     m_platformPlayer->prepareToPlay();
175 }
176
177 void MediaPlayerPrivate::play()
178 {
179     m_platformPlayer->play();
180 }
181
182 void MediaPlayerPrivate::pause()
183 {
184     m_platformPlayer->pause();
185 }
186
187 bool MediaPlayerPrivate::supportsFullscreen() const
188 {
189     return true;
190 }
191
192 IntSize MediaPlayerPrivate::naturalSize() const
193 {
194     // Cannot return empty size, otherwise paint() will never get called.
195     // Also, the values here will affect the aspect ratio of the output rectangle that will
196     // be used for renderering the video, so we must take PAR into account.
197     // Now, hope that metadata has been provided before this gets called if this is a video.
198     double pixelWidth = static_cast<double>(m_platformPlayer->pixelWidth());
199     double pixelHeight = static_cast<double>(m_platformPlayer->pixelHeight());
200     if (!m_platformPlayer->pixelWidth() || !m_platformPlayer->pixelHeight())
201         pixelWidth = pixelHeight = 1.0;
202
203     // Use floating point arithmetic to eliminate the chance of integer
204     // overflow. PAR numbers can be 5 digits or more.
205     double adjustedSourceWidth = static_cast<double>(m_platformPlayer->sourceWidth()) * pixelWidth / pixelHeight;
206     return IntSize(static_cast<int>(adjustedSourceWidth + 0.5), m_platformPlayer->sourceHeight());
207 }
208
209 bool MediaPlayerPrivate::hasVideo() const
210 {
211     return m_platformPlayer->hasVideo();
212 }
213
214 bool MediaPlayerPrivate::hasAudio() const
215 {
216     return m_platformPlayer->hasAudio();
217 }
218
219 void MediaPlayerPrivate::setVisible(bool)
220 {
221     notImplemented();
222 }
223
224 float MediaPlayerPrivate::duration() const
225 {
226     return m_platformPlayer->duration();
227 }
228
229 float MediaPlayerPrivate::currentTime() const
230 {
231     return m_userDrivenSeekTimer.isActive() ? m_lastSeekTime: m_platformPlayer->currentTime();
232 }
233
234 static const double SeekSubmissionDelay = 0.1; // Reasonable throttling value.
235
236 void MediaPlayerPrivate::seek(float time)
237 {
238     m_lastSeekTime = time;
239     if (!m_userDrivenSeekTimer.isActive())
240         m_userDrivenSeekTimer.startOneShot(SeekSubmissionDelay);
241 }
242
243 void MediaPlayerPrivate::userDrivenSeekTimerFired(Timer<MediaPlayerPrivate>*)
244 {
245     m_platformPlayer->seek(m_lastSeekTime);
246 }
247
248 bool MediaPlayerPrivate::seeking() const
249 {
250     return false;
251 }
252
253 void MediaPlayerPrivate::setRate(float rate)
254 {
255     m_platformPlayer->setRate(rate);
256 }
257
258 bool MediaPlayerPrivate::paused() const
259 {
260     return m_platformPlayer->paused();
261 }
262
263 void MediaPlayerPrivate::setVolume(float volume)
264 {
265     m_platformPlayer->setVolume(volume);
266 }
267
268 MediaPlayer::NetworkState MediaPlayerPrivate::networkState() const
269 {
270     return m_networkState;
271 }
272
273 MediaPlayer::ReadyState MediaPlayerPrivate::readyState() const
274 {
275     return m_readyState;
276 }
277
278 float MediaPlayerPrivate::maxTimeSeekable() const
279 {
280     return m_platformPlayer->maxTimeSeekable();
281 }
282
283 PassRefPtr<TimeRanges> MediaPlayerPrivate::buffered() const
284 {
285     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
286     if (float bufferLoaded = m_platformPlayer->bufferLoaded())
287         timeRanges->add(0, bufferLoaded);
288     return timeRanges.release();
289 }
290
291 unsigned MediaPlayerPrivate::bytesLoaded() const
292 {
293     notImplemented();
294     return 0;
295 }
296
297 void MediaPlayerPrivate::setSize(const IntSize&)
298 {
299     notImplemented();
300 }
301
302 void MediaPlayerPrivate::paint(GraphicsContext* context, const IntRect& rect)
303 {
304 #if USE(ACCELERATED_COMPOSITING)
305     // Only process paint calls coming via the accelerated compositing code
306     // path, where we get called with a null graphics context. See
307     // LayerCompositingThread::drawTextures(). Ignore calls from the regular
308     // rendering path.
309     if (!context)
310         m_platformPlayer->notifyOutputUpdate(BlackBerry::Platform::IntRect(rect.x(), rect.y(), rect.width(), rect.height()));
311     return;
312 #endif
313
314     if (!hasVideo() || context->paintingDisabled() || !m_webCorePlayer->visible())
315         return;
316
317     PlatformGraphicsContext* graphics = context->platformContext();
318     ASSERT(graphics);
319
320     BlackBerry::Platform::IntRect platformRect(rect.x(), rect.y(), rect.width(), rect.height());
321     IntRect clippedRect = frameView()->windowClipRect();
322     BlackBerry::Platform::IntRect platformWindowClipRect(clippedRect.x(), clippedRect.y(), clippedRect.width(), clippedRect.height());
323     m_platformPlayer->paint(graphics->canvas(), platformRect, platformWindowClipRect);
324 }
325
326 bool MediaPlayerPrivate::hasAvailableVideoFrame() const
327 {
328     return m_platformPlayer->hasAvailableVideoFrame();
329 }
330
331 bool MediaPlayerPrivate::hasSingleSecurityOrigin() const
332 {
333     return false;
334 }
335
336 MediaPlayer::MovieLoadType MediaPlayerPrivate::movieLoadType() const
337 {
338     return static_cast<MediaPlayer::MovieLoadType>(m_platformPlayer->movieLoadType());
339 }
340
341 // This function returns the user agent string associated with the
342 // frame loader client of our HTMLMediaElement. The call below will
343 // end up in FrameLoaderClientBlackBerry::userAgent().
344 String MediaPlayerPrivate::userAgent(const String& url) const
345 {
346     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
347     Document* topdoc = element->document()->topDocument();
348     ASSERT(topdoc->frame());
349     ASSERT(topdoc->frame()->loader());
350     if (topdoc->frame())
351         return topdoc->frame()->loader()->userAgent(KURL(KURL(), url));
352     return String();
353 }
354
355 void MediaPlayerPrivate::resizeSourceDimensions()
356 {
357     if (!m_webCorePlayer)
358         return;
359
360     HTMLMediaElement* client = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
361
362     if (!client || !client->isVideo())
363         return;
364
365     RenderObject* o = client->renderer();
366     if (!o)
367         return;
368
369     // If we have an HTMLVideoElement but the source has no video, then we need to resize the media element.
370     if (!hasVideo()) {
371         IntRect rect = o->enclosingBox()->contentBoxRect();
372
373         static const int playbookMinAudioElementWidth = 300;
374         static const int playbookMinAudioElementHeight = 32;
375         // If the rect dimensions are less than the allowed minimum, use the minimum instead.
376         int newWidth = max(rect.width(), playbookMinAudioElementWidth);
377         int newHeight = max(rect.height(), playbookMinAudioElementHeight);
378
379         char attrString[12];
380
381         sprintf(attrString, "%d", newWidth);
382         client->setAttribute(HTMLNames::widthAttr, attrString);
383
384         sprintf(attrString, "%d", newHeight);
385         client->setAttribute(HTMLNames::heightAttr, attrString);
386     }
387
388     // If we don't know what the width and height of the video source is, then we need to set it to something sane.
389     if (m_platformPlayer->sourceWidth() && m_platformPlayer->sourceHeight())
390         return;
391     IntRect rect = o->enclosingBox()->contentBoxRect();
392     m_platformPlayer->setSourceDimension(rect.width(), rect.height());
393 }
394
395 void MediaPlayerPrivate::setFullscreenWebPageClient(BlackBerry::WebKit::WebPageClient* client)
396 {
397     if (m_fullscreenWebPageClient == client)
398         return;
399
400     m_fullscreenWebPageClient = client;
401     m_platformPlayer->toggleFullscreen(client);
402
403     // The following repaint is needed especially if video is paused and
404     // fullscreen is exiting, so that a MediaPlayerPrivate::paint() is
405     // triggered and the code in outputUpdate() sets the correct window
406     // rectangle.
407     if (!client)
408         m_webCorePlayer->repaint();
409 }
410
411 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getWindow()
412 {
413     return m_platformPlayer->getWindow();
414 }
415
416 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::getPeerWindow(const char* uniqueID) const
417 {
418     return m_platformPlayer->getPeerWindow(uniqueID);
419 }
420
421 int MediaPlayerPrivate::getWindowPosition(unsigned& x, unsigned& y, unsigned& width, unsigned& height) const
422 {
423     return m_platformPlayer->getWindowPosition(x, y, width, height);
424 }
425
426 const char* MediaPlayerPrivate::mmrContextName()
427 {
428     return m_platformPlayer->mmrContextName();
429 }
430
431 float MediaPlayerPrivate::percentLoaded()
432 {
433     if (!m_platformPlayer->duration())
434         return 0;
435
436     float buffered = 0;
437     RefPtr<TimeRanges> timeRanges = this->buffered();
438     for (unsigned i = 0; i < timeRanges->length(); ++i) {
439         ExceptionCode ignoredException;
440         float start = timeRanges->start(i, ignoredException);
441         float end = timeRanges->end(i, ignoredException);
442         buffered += end - start;
443     }
444
445     float loaded = buffered / m_platformPlayer->duration();
446     return loaded;
447 }
448
449 unsigned MediaPlayerPrivate::sourceWidth()
450 {
451     return m_platformPlayer->sourceWidth();
452 }
453
454 unsigned MediaPlayerPrivate::sourceHeight()
455 {
456     return m_platformPlayer->sourceHeight();
457 }
458
459 void MediaPlayerPrivate::setAllowPPSVolumeUpdates(bool allow)
460 {
461     return m_platformPlayer->setAllowPPSVolumeUpdates(allow);
462 }
463
464 void MediaPlayerPrivate::updateStates()
465 {
466     MediaPlayer::NetworkState oldNetworkState = m_networkState;
467     MediaPlayer::ReadyState oldReadyState = m_readyState;
468
469     MMRPlayer::Error currentError = m_platformPlayer->error();
470
471     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
472
473     if (currentError != MMRPlayer::MediaOK) {
474         m_readyState = MediaPlayer::HaveNothing;
475         if (currentError == MMRPlayer::MediaDecodeError)
476             m_networkState = MediaPlayer::DecodeError;
477         else if (currentError == MMRPlayer::MediaMetaDataError
478             || currentError == MMRPlayer::MediaAudioReceiveError
479             || currentError == MMRPlayer::MediaVideoReceiveError)
480             m_networkState = MediaPlayer::NetworkError;
481     } else {
482         switch (m_platformPlayer->mediaState()) {
483         case MMRPlayer::MMRPlayStateIdle:
484             m_networkState = MediaPlayer::Idle;
485             break;
486         case MMRPlayer::MMRPlayStatePlaying:
487             m_networkState = MediaPlayer::Loading;
488             break;
489         case MMRPlayer::MMRPlayStateStopped:
490             m_networkState = MediaPlayer::Idle;
491             break;
492         case MMRPlayer::MMRPlayStateUnknown:
493         default:
494             break;
495         }
496
497         switch (m_platformPlayer->state()) {
498         case MMRPlayer::MP_STATE_IDLE:
499 #if USE(ACCELERATED_COMPOSITING)
500             setBuffering(false);
501             m_mediaIsBuffering = false;
502 #endif
503             if (isFullscreen())
504                 element->exitFullscreen();
505             break;
506         case MMRPlayer::MP_STATE_ACTIVE:
507 #if USE(ACCELERATED_COMPOSITING)
508             m_showBufferingImage = false;
509             m_mediaIsBuffering = false;
510 #endif
511             break;
512         case MMRPlayer::MP_STATE_UNSUPPORTED:
513             break;
514         default:
515             break;
516         }
517         if ((duration() || movieLoadType() == MediaPlayer::LiveStream)
518             && m_readyState != MediaPlayer::HaveEnoughData)
519             m_readyState = MediaPlayer::HaveEnoughData;
520     }
521
522     if (m_readyState != oldReadyState) {
523         m_webCorePlayer->readyStateChanged();
524 #if USE(ACCELERATED_COMPOSITING)
525         // Create platform layer for video.
526         if (!m_platformLayer)
527             m_platformLayer = VideoLayerWebKitThread::create(m_webCorePlayer);
528 #endif
529     }
530     if (m_networkState != oldNetworkState)
531         m_webCorePlayer->networkStateChanged();
532 }
533
534 // IMMRPlayerListener callbacks implementation
535 void MediaPlayerPrivate::onStateChanged(MMRPlayer::MpState)
536 {
537     updateStates();
538 }
539
540 void MediaPlayerPrivate::onMediaStatusChanged(MMRPlayer::MMRPlayState)
541 {
542     updateStates();
543 }
544
545 void MediaPlayerPrivate::onError(MMRPlayer::Error type)
546 {
547     updateStates();
548 }
549
550 void MediaPlayerPrivate::onDurationChanged(float duration)
551 {
552     updateStates();
553     m_webCorePlayer->durationChanged();
554 }
555
556 void MediaPlayerPrivate::onTimeChanged(float)
557 {
558     m_webCorePlayer->timeChanged();
559 }
560
561 void MediaPlayerPrivate::onPauseStateChanged()
562 {
563     if (!isFullscreen())
564         return;
565
566     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
567     // Paused state change not due to local controller.
568     if (m_platformPlayer->isPaused())
569         element->pause();
570     else {
571         // The HMI fullscreen widget has resumed play. Check if the
572         // pause timeout occurred.
573         m_platformPlayer->processPauseTimeoutIfNecessary();
574         element->play();
575     }
576 }
577
578 void MediaPlayerPrivate::onRateChanged(float)
579 {
580     m_webCorePlayer->rateChanged();
581 }
582
583 void MediaPlayerPrivate::onVolumeChanged(float volume)
584 {
585     m_webCorePlayer->volumeChanged(volume);
586 }
587
588 void MediaPlayerPrivate::onRepaint()
589 {
590     m_webCorePlayer->repaint();
591 }
592
593 void MediaPlayerPrivate::onSizeChanged()
594 {
595     resizeSourceDimensions();
596     if (hasVideo())
597         m_webCorePlayer->sizeChanged();
598 }
599
600 void MediaPlayerPrivate::onPlayNotified()
601 {
602     if (HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient()))
603         element->play();
604 }
605
606 void MediaPlayerPrivate::onPauseNotified()
607 {
608     if (HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient()))
609         element->pause();
610 }
611
612 static const int popupDialogInterval = 10;
613 static const double checkMetadataReadyInterval = 0.5;
614 void MediaPlayerPrivate::onWaitMetadataNotified(bool hasFinished, int timeWaited)
615 {
616     if (!hasFinished) {
617         if (!m_waitMetadataTimer.isActive()) {
618             // Make sure to popup dialog every 10 seconds after metadata start to load.
619             // This should be set only once at the first time when user press the play button.
620             m_waitMetadataPopDialogCounter = static_cast<int>(timeWaited / checkMetadataReadyInterval);
621             m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
622         }
623     } else if (m_waitMetadataTimer.isActive()) {
624         m_waitMetadataTimer.stop();
625         m_waitMetadataPopDialogCounter = 0;
626     }
627 }
628
629 void MediaPlayerPrivate::waitMetadataTimerFired(Timer<MediaPlayerPrivate>*)
630 {
631     if (m_platformPlayer->isMetadataReady()) {
632         m_platformPlayer->playWithMetadataReady();
633         m_waitMetadataPopDialogCounter = 0;
634         return;
635     }
636
637     static const int hitTimeToPopupDialog = static_cast<int>(popupDialogInterval / checkMetadataReadyInterval);
638     m_waitMetadataPopDialogCounter++;
639     if (m_waitMetadataPopDialogCounter < hitTimeToPopupDialog) {
640         m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
641         return;
642     }
643     m_waitMetadataPopDialogCounter = 0;
644
645     int wait = showErrorDialog(MMRPlayer::MediaMetaDataTimeoutError);
646     if (!wait)
647         onPauseNotified();
648     else {
649         if (m_platformPlayer->isMetadataReady())
650             m_platformPlayer->playWithMetadataReady();
651         else
652             m_waitMetadataTimer.startOneShot(checkMetadataReadyInterval);
653     }
654 }
655
656 #if USE(ACCELERATED_COMPOSITING)
657 void MediaPlayerPrivate::onBuffering(bool flag)
658 {
659     setBuffering(flag);
660 }
661 #endif
662
663 static ProtectionSpace generateProtectionSpaceFromMMRAuthChallenge(const MMRAuthChallenge& authChallenge)
664 {
665     KURL url(ParsedURLString, String(authChallenge.url().c_str()));
666     ASSERT(url.isValid());
667
668     return ProtectionSpace(url.host(), url.port(),
669                            static_cast<ProtectionSpaceServerType>(authChallenge.serverType()),
670                            authChallenge.realm().c_str(),
671                            static_cast<ProtectionSpaceAuthenticationScheme>(authChallenge.authScheme()));
672 }
673
674 bool MediaPlayerPrivate::onAuthenticationNeeded(MMRAuthChallenge& authChallenge)
675 {
676     KURL url(ParsedURLString, String(authChallenge.url().c_str()));
677     if (!url.isValid())
678         return false;
679
680     ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
681     Credential credential = CredentialStorage::get(protectionSpace);
682     bool isConfirmed = false;
683     if (credential.isEmpty()) {
684         if (frameView() && frameView()->hostWindow())
685             isConfirmed = frameView()->hostWindow()->platformPageClient()->authenticationChallenge(url, protectionSpace, credential);
686     } else
687         isConfirmed = true;
688
689     if (isConfirmed)
690         authChallenge.setCredential(credential.user().utf8().data(), credential.password().utf8().data(), static_cast<MMRAuthChallenge::CredentialPersistence>(credential.persistence()));
691
692     return isConfirmed;
693 }
694
695 void MediaPlayerPrivate::onAuthenticationAccepted(const MMRAuthChallenge& authChallenge) const
696 {
697     KURL url(ParsedURLString, String(authChallenge.url().c_str()));
698     if (!url.isValid())
699         return;
700
701     ProtectionSpace protectionSpace = generateProtectionSpaceFromMMRAuthChallenge(authChallenge);
702     Credential savedCredential = CredentialStorage::get(protectionSpace);
703     if (savedCredential.isEmpty())
704         CredentialStorage::set(Credential(authChallenge.username().c_str(), authChallenge.password().c_str(), static_cast<CredentialPersistence>(authChallenge.persistence())), protectionSpace, url);
705 }
706
707 int MediaPlayerPrivate::showErrorDialog(MMRPlayer::Error type)
708 {
709     using namespace BlackBerry::WebKit;
710
711     WebPageClient::AlertType atype;
712     switch (type) {
713     case MMRPlayer::MediaOK:
714         atype = WebPageClient::MediaOK;
715         break;
716     case MMRPlayer::MediaDecodeError:
717         atype = WebPageClient::MediaDecodeError;
718         break;
719     case MMRPlayer::MediaMetaDataError:
720         atype = WebPageClient::MediaMetaDataError;
721         break;
722     case MMRPlayer::MediaMetaDataTimeoutError:
723         atype = WebPageClient::MediaMetaDataTimeoutError;
724         break;
725     case MMRPlayer::MediaNoMetaDataError:
726         atype = WebPageClient::MediaNoMetaDataError;
727         break;
728     case MMRPlayer::MediaVideoReceiveError:
729         atype = WebPageClient::MediaVideoReceiveError;
730         break;
731     case MMRPlayer::MediaAudioReceiveError:
732         atype = WebPageClient::MediaAudioReceiveError;
733         break;
734     case MMRPlayer::MediaInvalidError:
735         atype = WebPageClient::MediaInvalidError;
736         break;
737     default:
738         LOG(Media, "Alert type does not exist.");
739         return -1;
740     }
741
742     int rc = 0;
743     if (frameView() && frameView()->hostWindow())
744         rc = frameView()->hostWindow()->platformPageClient()->showAlertDialog(atype);
745     return rc;
746 }
747
748 FrameView* MediaPlayerPrivate::frameView() const
749 {
750     // We previously used m_webCorePlayer->frameView(), but this method returns
751     // a null frameView until quite late in the media player initialization,
752     // and starting quite early in the media player destruction (because
753     // it may be set to zero by the destructor in RenderVideo.cpp before
754     // our destructor is called, leaving us unable to clean up child windows
755     // in mmrDisconnect).
756     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
757     return element->document()->view();
758 }
759
760 BlackBerry::Platform::Graphics::Window* MediaPlayerPrivate::platformWindow()
761 {
762     if (frameView() && frameView()->hostWindow())
763         return frameView()->hostWindow()->platformPageClient()->platformWindow();
764     return 0;
765 }
766
767 bool MediaPlayerPrivate::isFullscreen() const
768 {
769     return m_fullscreenWebPageClient;
770 }
771
772 bool MediaPlayerPrivate::isElementPaused() const
773 {
774     HTMLMediaElement* element = static_cast<HTMLMediaElement*>(m_webCorePlayer->mediaPlayerClient());
775     if (!element || element->paused())
776         return true;
777     return false;
778 }
779
780 bool MediaPlayerPrivate::isTabVisible() const
781 {
782     if (frameView() && frameView()->hostWindow())
783         return frameView()->hostWindow()->platformPageClient()->isVisible();
784     return true;
785 }
786
787 #if USE(ACCELERATED_COMPOSITING)
788 static const double BufferingAnimationDelay = 1.0 / 24;
789 static char* s_bufferingImageData = 0;
790 static int s_bufferingImageWidth = 0;
791 static int s_bufferingImageHeight = 0;
792
793 PlatformMedia MediaPlayerPrivate::platformMedia() const
794 {
795     PlatformMedia pm;
796     pm.type = PlatformMedia::QNXMediaPlayerType;
797     pm.media.qnxMediaPlayer = const_cast<MediaPlayerPrivate*>(this);
798     return pm;
799 }
800
801 PlatformLayer* MediaPlayerPrivate::platformLayer() const
802 {
803     if (m_platformLayer)
804         return m_platformLayer.get();
805     return 0;
806 }
807
808 static void loadBufferingImageData()
809 {
810     static bool loaded = false;
811     if (!loaded) {
812         static Image* bufferingIcon = Image::loadPlatformResource("vidbuffer").leakRef();
813         NativeImageSkia* nativeImage = bufferingIcon->nativeImageForCurrentFrame();
814         if (!nativeImage)
815             return;
816
817         if (!nativeImage->isDataComplete())
818             return;
819
820         loaded = true;
821         nativeImage->bitmap().lockPixels();
822
823         int bufSize = nativeImage->bitmap().width() * nativeImage->bitmap().height() * 4;
824         s_bufferingImageWidth = nativeImage->bitmap().width();
825         s_bufferingImageHeight = nativeImage->bitmap().height();
826         s_bufferingImageData = static_cast<char*>(malloc(bufSize));
827         memcpy(s_bufferingImageData, nativeImage->bitmap().getPixels(), bufSize);
828
829         nativeImage->bitmap().unlockPixels();
830         bufferingIcon->deref();
831     }
832 }
833
834 void MediaPlayerPrivate::bufferingTimerFired(Timer<MediaPlayerPrivate>*)
835 {
836     if (m_showBufferingImage) {
837         if (!isFullscreen() && m_platformLayer)
838             m_platformLayer->setNeedsDisplay();
839         m_bufferingTimer.startOneShot(BufferingAnimationDelay);
840     }
841 }
842
843 void MediaPlayerPrivate::setBuffering(bool buffering)
844 {
845     if (!hasVideo())
846         buffering = false; // Buffering animation not visible for audio.
847     if (buffering != m_showBufferingImage) {
848         m_showBufferingImage = buffering;
849         if (buffering) {
850             loadBufferingImageData();
851             m_bufferingTimer.startOneShot(BufferingAnimationDelay);
852         } else
853             m_bufferingTimer.stop();
854
855         if (m_platformLayer)
856             m_platformLayer->setNeedsDisplay();
857     }
858 }
859
860 static unsigned int allocateTextureId()
861 {
862     unsigned int texid;
863     glGenTextures(1, &texid);
864     glBindTexture(GL_TEXTURE_2D, texid);
865     // Do basic linear filtering on resize.
866     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
867     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
868     // NPOT textures in GL ES only work when the wrap mode is set to GL_CLAMP_TO_EDGE.
869     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
870     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
871     return texid;
872 }
873
874 void MediaPlayerPrivate::drawBufferingAnimation(const TransformationMatrix& matrix, int positionLocation, int texCoordLocation)
875 {
876     if (m_showBufferingImage && s_bufferingImageData && !isFullscreen()) {
877         TransformationMatrix renderMatrix = matrix;
878
879         // Rotate the buffering indicator so that it takes 1 second to do 1 revolution.
880         timespec time;
881         clock_gettime(CLOCK_REALTIME, &time);
882         renderMatrix.rotate(time.tv_nsec / 1000000000.0 * 360.0);
883
884         static bool initialized = false;
885         static unsigned int texId = allocateTextureId();
886         glBindTexture(GL_TEXTURE_2D, texId);
887         if (!initialized) {
888             initialized = true;
889             glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, s_bufferingImageWidth, s_bufferingImageHeight,
890                 0, GL_RGBA, GL_UNSIGNED_BYTE, s_bufferingImageData);
891             free(s_bufferingImageData);
892         }
893
894         float texcoords[] = { 0, 0,  0, 1,  1, 1,  1, 0 };
895         FloatPoint vertices[4];
896         float bx = s_bufferingImageWidth / 2.0;
897         float by = s_bufferingImageHeight / 2.0;
898         vertices[0] = renderMatrix.mapPoint(FloatPoint(-bx, -by));
899         vertices[1] = renderMatrix.mapPoint(FloatPoint(-bx, by));
900         vertices[2] = renderMatrix.mapPoint(FloatPoint(bx, by));
901         vertices[3] = renderMatrix.mapPoint(FloatPoint(bx, -by));
902
903         glVertexAttribPointer(positionLocation, 2, GL_FLOAT, GL_FALSE, 0, vertices);
904         glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
905         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
906     }
907 }
908 #endif
909
910 } // namespace WebCore
911
912 #endif // ENABLE(VIDEO)