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