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