initial import
[vuplus_webkit] / Source / WebCore / platform / graphics / win / MediaPlayerPrivateQuickTimeVisualContext.cpp
1 /*
2  * Copyright (C) 2007, 2008, 2009, 2010, 2011 Apple, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27
28 #if ENABLE(VIDEO)
29 #include "MediaPlayerPrivateQuickTimeVisualContext.h"
30
31 #include "Cookie.h"
32 #include "CookieJar.h"
33 #include "DocumentLoader.h"
34 #include "Frame.h"
35 #include "FrameView.h"
36 #include "GraphicsContext.h"
37 #include "KURL.h"
38 #include "MediaPlayerPrivateTaskTimer.h"
39 #include "Page.h"
40 #include "QTCFDictionary.h"
41 #include "QTDecompressionSession.h"
42 #include "QTMovie.h"
43 #include "QTMovieTask.h"
44 #include "QTMovieVisualContext.h"
45 #include "ScrollView.h"
46 #include "Settings.h"
47 #include "SoftLinking.h"
48 #include "TimeRanges.h"
49 #include "Timer.h"
50 #include <AssertMacros.h>
51 #include <CoreGraphics/CGAffineTransform.h>
52 #include <CoreGraphics/CGContext.h>
53 #include <QuartzCore/CATransform3D.h>
54 #include <Wininet.h>
55 #include <wtf/CurrentTime.h>
56 #include <wtf/HashSet.h>
57 #include <wtf/MainThread.h>
58 #include <wtf/MathExtras.h>
59 #include <wtf/StdLibExtras.h>
60 #include <wtf/text/StringBuilder.h>
61 #include <wtf/text/StringHash.h>
62
63 #if USE(ACCELERATED_COMPOSITING)
64 #include "PlatformCALayer.h"
65 #include "WKCAImageQueue.h"
66 #endif
67
68 using namespace std;
69
70 namespace WebCore {
71
72 static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer);
73 static bool requiredDllsAvailable();
74
75 SOFT_LINK_LIBRARY(Wininet)
76 SOFT_LINK(Wininet, InternetSetCookieExW, DWORD, WINAPI, (LPCWSTR lpszUrl, LPCWSTR lpszCookieName, LPCWSTR lpszCookieData, DWORD dwFlags, DWORD_PTR dwReserved), (lpszUrl, lpszCookieName, lpszCookieData, dwFlags, dwReserved))
77
78 // Interface declaration for MediaPlayerPrivateQuickTimeVisualContext's QTMovieClient aggregate
79 class MediaPlayerPrivateQuickTimeVisualContext::MovieClient : public QTMovieClient {
80 public:
81     MovieClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
82     virtual ~MovieClient() { m_parent = 0; }
83     virtual void movieEnded(QTMovie*);
84     virtual void movieLoadStateChanged(QTMovie*);
85     virtual void movieTimeChanged(QTMovie*);
86 private:
87     MediaPlayerPrivateQuickTimeVisualContext* m_parent;
88 };
89
90 #if USE(ACCELERATED_COMPOSITING)
91 class MediaPlayerPrivateQuickTimeVisualContext::LayerClient : public PlatformCALayerClient {
92 public:
93     LayerClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
94     virtual ~LayerClient() { m_parent = 0; }
95
96 private:
97     virtual void platformCALayerLayoutSublayersOfLayer(PlatformCALayer*);
98     virtual bool platformCALayerRespondsToLayoutChanges() const { return true; }
99
100     virtual void platformCALayerAnimationStarted(CFTimeInterval beginTime) { }
101     virtual GraphicsLayer::CompositingCoordinatesOrientation platformCALayerContentsOrientation() const { return GraphicsLayer::CompositingCoordinatesBottomUp; }
102     virtual void platformCALayerPaintContents(GraphicsContext&, const IntRect& inClip) { }
103     virtual bool platformCALayerShowDebugBorders() const { return false; }
104     virtual bool platformCALayerShowRepaintCounter() const { return false; }
105     virtual int platformCALayerIncrementRepaintCount() { return 0; }
106
107     virtual bool platformCALayerContentsOpaque() const { return false; }
108     virtual bool platformCALayerDrawsContent() const { return false; }
109     virtual void platformCALayerLayerDidDisplay(PlatformLayer*) { }
110
111     MediaPlayerPrivateQuickTimeVisualContext* m_parent;
112 };
113
114 void MediaPlayerPrivateQuickTimeVisualContext::LayerClient::platformCALayerLayoutSublayersOfLayer(PlatformCALayer* layer)
115 {
116     ASSERT(m_parent);
117     ASSERT(m_parent->m_transformLayer == layer);
118
119     FloatSize parentSize = layer->bounds().size();
120     FloatSize naturalSize = m_parent->naturalSize();
121
122     // Calculate the ratio of these two sizes and use that ratio to scale the qtVideoLayer:
123     FloatSize ratio(parentSize.width() / naturalSize.width(), parentSize.height() / naturalSize.height());
124
125     int videoWidth = 0;
126     int videoHeight = 0;
127     m_parent->m_movie->getNaturalSize(videoWidth, videoHeight);
128     FloatRect videoBounds(0, 0, videoWidth * ratio.width(), videoHeight * ratio.height());
129     FloatPoint3D videoAnchor = m_parent->m_qtVideoLayer->anchorPoint();
130
131     // Calculate the new position based on the parent's size:
132     FloatPoint position(parentSize.width() * 0.5 - videoBounds.width() * (0.5 - videoAnchor.x()),
133         parentSize.height() * 0.5 - videoBounds.height() * (0.5 - videoAnchor.y())); 
134
135     m_parent->m_qtVideoLayer->setBounds(videoBounds);
136     m_parent->m_qtVideoLayer->setPosition(position);
137 }
138 #endif
139
140 class MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient : public QTMovieVisualContextClient {
141 public:
142     VisualContextClient(MediaPlayerPrivateQuickTimeVisualContext* parent) : m_parent(parent) {}
143     virtual ~VisualContextClient() { m_parent = 0; }
144     void imageAvailableForTime(const QTCVTimeStamp*);
145     static void retrieveCurrentImageProc(void*);
146 private:
147     MediaPlayerPrivateQuickTimeVisualContext* m_parent;
148 };
149
150 PassOwnPtr<MediaPlayerPrivateInterface> MediaPlayerPrivateQuickTimeVisualContext::create(MediaPlayer* player)
151
152     return adoptPtr(new MediaPlayerPrivateQuickTimeVisualContext(player));
153 }
154
155 void MediaPlayerPrivateQuickTimeVisualContext::registerMediaEngine(MediaEngineRegistrar registrar)
156 {
157     if (isAvailable())
158         registrar(create, getSupportedTypes, supportsType, 0, 0, 0);
159 }
160
161 MediaPlayerPrivateQuickTimeVisualContext::MediaPlayerPrivateQuickTimeVisualContext(MediaPlayer* player)
162     : m_player(player)
163     , m_seekTo(-1)
164     , m_seekTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired)
165     , m_visualContextTimer(this, &MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired)
166     , m_networkState(MediaPlayer::Empty)
167     , m_readyState(MediaPlayer::HaveNothing)
168     , m_enabledTrackCount(0)
169     , m_totalTrackCount(0)
170     , m_hasUnsupportedTracks(false)
171     , m_startedPlaying(false)
172     , m_isStreaming(false)
173     , m_visible(false)
174     , m_newFrameAvailable(false)
175     , m_movieClient(adoptPtr(new MediaPlayerPrivateQuickTimeVisualContext::MovieClient(this)))
176 #if USE(ACCELERATED_COMPOSITING)
177     , m_layerClient(adoptPtr(new MediaPlayerPrivateQuickTimeVisualContext::LayerClient(this)))
178     , m_movieTransform(CGAffineTransformIdentity)
179 #endif
180     , m_visualContextClient(adoptPtr(new MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient(this)))
181     , m_delayingLoad(false)
182     , m_privateBrowsing(false)
183     , m_preload(MediaPlayer::Auto)
184 {
185 }
186
187 MediaPlayerPrivateQuickTimeVisualContext::~MediaPlayerPrivateQuickTimeVisualContext()
188 {
189     tearDownVideoRendering();
190     cancelCallOnMainThread(&VisualContextClient::retrieveCurrentImageProc, this);
191 }
192
193 bool MediaPlayerPrivateQuickTimeVisualContext::supportsFullscreen() const
194 {
195 #if USE(ACCELERATED_COMPOSITING)
196     Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument(); 
197     if (document && document->settings())
198         return document->settings()->acceleratedCompositingEnabled();
199 #endif
200     return false;
201 }
202
203 PlatformMedia MediaPlayerPrivateQuickTimeVisualContext::platformMedia() const
204 {
205     PlatformMedia p;
206     p.type = PlatformMedia::QTMovieVisualContextType;
207     p.media.qtMovieVisualContext = m_visualContext.get();
208     return p;
209 }
210 #if USE(ACCELERATED_COMPOSITING)
211
212 PlatformLayer* MediaPlayerPrivateQuickTimeVisualContext::platformLayer() const
213 {
214     return m_transformLayer ? m_transformLayer->platformLayer() : 0;
215 }
216 #endif
217
218 String MediaPlayerPrivateQuickTimeVisualContext::rfc2616DateStringFromTime(CFAbsoluteTime time)
219 {
220     static const char* const dayStrings[] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
221     static const char* const monthStrings[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
222     static const CFStringRef dateFormatString = CFSTR("%s, %02d %s %04d %02d:%02d:%02d GMT");
223     static CFTimeZoneRef gmtTimeZone;
224     if (!gmtTimeZone)
225         gmtTimeZone = CFTimeZoneCopyDefault();
226
227     CFGregorianDate dateValue = CFAbsoluteTimeGetGregorianDate(time, gmtTimeZone); 
228     if (!CFGregorianDateIsValid(dateValue, kCFGregorianAllUnits))
229         return String();
230
231     time = CFGregorianDateGetAbsoluteTime(dateValue, gmtTimeZone);
232     SInt32 day = CFAbsoluteTimeGetDayOfWeek(time, 0);
233
234     RetainPtr<CFStringRef> dateCFString(AdoptCF, CFStringCreateWithFormat(0, 0, dateFormatString, dayStrings[day - 1], dateValue.day, 
235         monthStrings[dateValue.month - 1], dateValue.year, dateValue.hour, dateValue.minute, (int)dateValue.second));
236     return dateCFString.get();
237 }
238
239 static void addCookieParam(StringBuilder& cookieBuilder, const String& name, const String& value)
240 {
241     if (name.isEmpty())
242         return;
243
244     // If this isn't the first parameter added, terminate the previous one.
245     if (cookieBuilder.length())
246         cookieBuilder.append("; ");
247
248     // Add parameter name, and value if there is one.
249     cookieBuilder.append(name);
250     if (!value.isEmpty()) {
251         cookieBuilder.append('=');
252         cookieBuilder.append(value);
253     }
254 }
255
256 void MediaPlayerPrivateQuickTimeVisualContext::setUpCookiesForQuickTime(const String& url)
257 {
258     // WebCore loaded the page with the movie URL with CFNetwork but QuickTime will 
259     // use WinINet to download the movie, so we need to copy any cookies needed to
260     // download the movie into WinInet before asking QuickTime to open it.
261     Document* document = m_player->mediaPlayerClient()->mediaPlayerOwningDocument();
262     Frame* frame = document ? document->frame() : 0;
263     if (!frame || !frame->page() || !frame->page()->cookieEnabled())
264         return;
265
266     KURL movieURL = KURL(KURL(), url);
267     Vector<Cookie> documentCookies;
268     if (!getRawCookies(frame->document(), movieURL, documentCookies))
269         return;
270
271     for (size_t ndx = 0; ndx < documentCookies.size(); ndx++) {
272         const Cookie& cookie = documentCookies[ndx];
273
274         if (cookie.name.isEmpty())
275             continue;
276
277         // Build up the cookie string with as much information as we can get so WinINet
278         // knows what to do with it.
279         StringBuilder cookieBuilder;
280         addCookieParam(cookieBuilder, cookie.name, cookie.value);
281         addCookieParam(cookieBuilder, "path", cookie.path);
282         if (cookie.expires) 
283             addCookieParam(cookieBuilder, "expires", rfc2616DateStringFromTime(cookie.expires));
284         if (cookie.httpOnly) 
285             addCookieParam(cookieBuilder, "httpOnly", String());
286         cookieBuilder.append(';');
287
288         String cookieURL;
289         if (!cookie.domain.isEmpty()) {
290             StringBuilder urlBuilder;
291
292             urlBuilder.append(movieURL.protocol());
293             urlBuilder.append("://");
294             if (cookie.domain[0] == '.')
295                 urlBuilder.append(cookie.domain.substring(1));
296             else
297                 urlBuilder.append(cookie.domain);
298             if (cookie.path.length() > 1)
299                 urlBuilder.append(cookie.path);
300
301             cookieURL = urlBuilder.toString();
302         } else
303             cookieURL = movieURL;
304
305         InternetSetCookieExW(cookieURL.charactersWithNullTermination(), 0, cookieBuilder.toString().charactersWithNullTermination(), 0, 0);
306     }
307 }
308
309 static void disableComponentsOnce()
310 {
311     static bool sComponentsDisabled = false;
312     if (sComponentsDisabled)
313         return;
314     sComponentsDisabled = true;
315
316     uint32_t componentsToDisable[][5] = {
317         {'eat ', 'TEXT', 'text', 0, 0},
318         {'eat ', 'TXT ', 'text', 0, 0},    
319         {'eat ', 'utxt', 'text', 0, 0},  
320         {'eat ', 'TEXT', 'tx3g', 0, 0},  
321     };
322
323     for (size_t i = 0; i < WTF_ARRAY_LENGTH(componentsToDisable); ++i) 
324         QTMovie::disableComponent(componentsToDisable[i]);
325 }
326
327 void MediaPlayerPrivateQuickTimeVisualContext::resumeLoad()
328 {
329     m_delayingLoad = false;
330
331     if (!m_movieURL.isEmpty())
332         loadInternal(m_movieURL);
333 }
334
335 void MediaPlayerPrivateQuickTimeVisualContext::load(const String& url)
336 {
337     m_movieURL = url;
338
339     if (m_preload == MediaPlayer::None) {
340         m_delayingLoad = true;
341         return;
342     }
343
344     loadInternal(url);
345 }
346
347 void MediaPlayerPrivateQuickTimeVisualContext::loadInternal(const String& url)
348 {
349     if (!QTMovie::initializeQuickTime()) {
350         // FIXME: is this the right error to return?
351         m_networkState = MediaPlayer::DecodeError; 
352         m_player->networkStateChanged();
353         return;
354     }
355
356     disableComponentsOnce();
357
358     // Initialize the task timer.
359     MediaPlayerPrivateTaskTimer::initialize();
360
361     if (m_networkState != MediaPlayer::Loading) {
362         m_networkState = MediaPlayer::Loading;
363         m_player->networkStateChanged();
364     }
365     if (m_readyState != MediaPlayer::HaveNothing) {
366         m_readyState = MediaPlayer::HaveNothing;
367         m_player->readyStateChanged();
368     }
369     cancelSeek();
370
371     setUpCookiesForQuickTime(url);
372
373     m_movie = adoptRef(new QTMovie(m_movieClient.get()));
374
375     m_movie->load(url.characters(), url.length(), m_player->preservesPitch());
376     m_movie->setVolume(m_player->volume());
377 }
378
379 void MediaPlayerPrivateQuickTimeVisualContext::prepareToPlay()
380 {
381     if (!m_movie || m_delayingLoad)
382         resumeLoad();
383 }
384
385 void MediaPlayerPrivateQuickTimeVisualContext::play()
386 {
387     if (!m_movie)
388         return;
389     m_startedPlaying = true;
390
391     m_movie->play();
392     m_visualContextTimer.startRepeating(1.0 / 30);
393 }
394
395 void MediaPlayerPrivateQuickTimeVisualContext::pause()
396 {
397     if (!m_movie)
398         return;
399     m_startedPlaying = false;
400
401     m_movie->pause();
402     m_visualContextTimer.stop();
403 }
404
405 float MediaPlayerPrivateQuickTimeVisualContext::duration() const
406 {
407     if (!m_movie)
408         return 0;
409     return m_movie->duration();
410 }
411
412 float MediaPlayerPrivateQuickTimeVisualContext::currentTime() const
413 {
414     if (!m_movie)
415         return 0;
416     return m_movie->currentTime();
417 }
418
419 void MediaPlayerPrivateQuickTimeVisualContext::seek(float time)
420 {
421     cancelSeek();
422     
423     if (!m_movie)
424         return;
425     
426     if (time > duration())
427         time = duration();
428     
429     m_seekTo = time;
430     if (maxTimeLoaded() >= m_seekTo)
431         doSeek();
432     else 
433         m_seekTimer.start(0, 0.5f);
434 }
435     
436 void MediaPlayerPrivateQuickTimeVisualContext::doSeek() 
437 {
438     float oldRate = m_movie->rate();
439     if (oldRate)
440         m_movie->setRate(0);
441     m_movie->setCurrentTime(m_seekTo);
442     float timeAfterSeek = currentTime();
443     // restore playback only if not at end, othewise QTMovie will loop
444     if (oldRate && timeAfterSeek < duration())
445         m_movie->setRate(oldRate);
446     cancelSeek();
447 }
448
449 void MediaPlayerPrivateQuickTimeVisualContext::cancelSeek()
450 {
451     m_seekTo = -1;
452     m_seekTimer.stop();
453 }
454
455 void MediaPlayerPrivateQuickTimeVisualContext::seekTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
456 {        
457     if (!m_movie || !seeking() || currentTime() == m_seekTo) {
458         cancelSeek();
459         updateStates();
460         m_player->timeChanged(); 
461         return;
462     } 
463     
464     if (maxTimeLoaded() >= m_seekTo)
465         doSeek();
466     else {
467         MediaPlayer::NetworkState state = networkState();
468         if (state == MediaPlayer::Empty || state == MediaPlayer::Loaded) {
469             cancelSeek();
470             updateStates();
471             m_player->timeChanged();
472         }
473     }
474 }
475
476 bool MediaPlayerPrivateQuickTimeVisualContext::paused() const
477 {
478     if (!m_movie)
479         return true;
480     return (!m_movie->rate());
481 }
482
483 bool MediaPlayerPrivateQuickTimeVisualContext::seeking() const
484 {
485     if (!m_movie)
486         return false;
487     return m_seekTo >= 0;
488 }
489
490 IntSize MediaPlayerPrivateQuickTimeVisualContext::naturalSize() const
491 {
492     if (!m_movie)
493         return IntSize();
494     int width;
495     int height;
496     m_movie->getNaturalSize(width, height);
497 #if USE(ACCELERATED_COMPOSITING)
498     CGSize originalSize = {width, height};
499     CGSize transformedSize = CGSizeApplyAffineTransform(originalSize, m_movieTransform);
500     return IntSize(abs(transformedSize.width), abs(transformedSize.height));
501 #else
502     return IntSize(width, height);
503 #endif
504 }
505
506 bool MediaPlayerPrivateQuickTimeVisualContext::hasVideo() const
507 {
508     if (!m_movie)
509         return false;
510     return m_movie->hasVideo();
511 }
512
513 bool MediaPlayerPrivateQuickTimeVisualContext::hasAudio() const
514 {
515     if (!m_movie)
516         return false;
517     return m_movie->hasAudio();
518 }
519
520 void MediaPlayerPrivateQuickTimeVisualContext::setVolume(float volume)
521 {
522     if (!m_movie)
523         return;
524     m_movie->setVolume(volume);
525 }
526
527 void MediaPlayerPrivateQuickTimeVisualContext::setRate(float rate)
528 {
529     if (!m_movie)
530         return;
531
532     // Do not call setRate(...) unless we have started playing; otherwise
533     // QuickTime's VisualContext can get wedged waiting for a rate change
534     // call which will never come.
535     if (m_startedPlaying)
536         m_movie->setRate(rate);
537 }
538
539 void MediaPlayerPrivateQuickTimeVisualContext::setPreservesPitch(bool preservesPitch)
540 {
541     if (!m_movie)
542         return;
543     m_movie->setPreservesPitch(preservesPitch);
544 }
545
546 bool MediaPlayerPrivateQuickTimeVisualContext::hasClosedCaptions() const
547 {
548     if (!m_movie)
549         return false;
550     return m_movie->hasClosedCaptions();
551 }
552
553 void MediaPlayerPrivateQuickTimeVisualContext::setClosedCaptionsVisible(bool visible)
554 {
555     if (!m_movie)
556         return;
557     m_movie->setClosedCaptionsVisible(visible);
558 }
559
560 PassRefPtr<TimeRanges> MediaPlayerPrivateQuickTimeVisualContext::buffered() const
561 {
562     RefPtr<TimeRanges> timeRanges = TimeRanges::create();
563     float loaded = maxTimeLoaded();
564     // rtsp streams are not buffered
565     if (!m_isStreaming && loaded > 0)
566         timeRanges->add(0, loaded);
567     return timeRanges.release();
568 }
569
570 float MediaPlayerPrivateQuickTimeVisualContext::maxTimeSeekable() const
571 {
572     // infinite duration means live stream
573     return !isfinite(duration()) ? 0 : maxTimeLoaded();
574 }
575
576 float MediaPlayerPrivateQuickTimeVisualContext::maxTimeLoaded() const
577 {
578     if (!m_movie)
579         return 0;
580     return m_movie->maxTimeLoaded(); 
581 }
582
583 unsigned MediaPlayerPrivateQuickTimeVisualContext::bytesLoaded() const
584 {
585     if (!m_movie)
586         return 0;
587     float dur = duration();
588     float maxTime = maxTimeLoaded();
589     if (!dur)
590         return 0;
591     return totalBytes() * maxTime / dur;
592 }
593
594 unsigned MediaPlayerPrivateQuickTimeVisualContext::totalBytes() const
595 {
596     if (!m_movie)
597         return 0;
598     return m_movie->dataSize();
599 }
600
601 void MediaPlayerPrivateQuickTimeVisualContext::cancelLoad()
602 {
603     if (m_networkState < MediaPlayer::Loading || m_networkState == MediaPlayer::Loaded)
604         return;
605     
606     tearDownVideoRendering();
607
608     // Cancel the load by destroying the movie.
609     m_movie.clear();
610
611     updateStates();
612 }
613
614 void MediaPlayerPrivateQuickTimeVisualContext::updateStates()
615 {
616     MediaPlayer::NetworkState oldNetworkState = m_networkState;
617     MediaPlayer::ReadyState oldReadyState = m_readyState;
618   
619     long loadState = m_movie ? m_movie->loadState() : QTMovieLoadStateError;
620
621     if (loadState >= QTMovieLoadStateLoaded && m_readyState < MediaPlayer::HaveMetadata) {
622         m_movie->disableUnsupportedTracks(m_enabledTrackCount, m_totalTrackCount);
623         if (m_player->inMediaDocument()) {
624             if (!m_enabledTrackCount || m_enabledTrackCount != m_totalTrackCount) {
625                 // This is a type of media that we do not handle directly with a <video> 
626                 // element, eg. QuickTime VR, a movie with a sprite track, etc. Tell the 
627                 // MediaPlayerClient that we won't support it.
628                 sawUnsupportedTracks();
629                 return;
630             }
631         } else if (!m_enabledTrackCount)
632             loadState = QTMovieLoadStateError;
633     }
634
635     // "Loaded" is reserved for fully buffered movies, never the case when streaming
636     if (loadState >= QTMovieLoadStateComplete && !m_isStreaming) {
637         m_networkState = MediaPlayer::Loaded;
638         m_readyState = MediaPlayer::HaveEnoughData;
639     } else if (loadState >= QTMovieLoadStatePlaythroughOK) {
640         m_readyState = MediaPlayer::HaveEnoughData;
641     } else if (loadState >= QTMovieLoadStatePlayable) {
642         // FIXME: This might not work correctly in streaming case, <rdar://problem/5693967>
643         m_readyState = currentTime() < maxTimeLoaded() ? MediaPlayer::HaveFutureData : MediaPlayer::HaveCurrentData;
644     } else if (loadState >= QTMovieLoadStateLoaded) {
645         m_readyState = MediaPlayer::HaveMetadata;
646     } else if (loadState > QTMovieLoadStateError) {
647         m_networkState = MediaPlayer::Loading;
648         m_readyState = MediaPlayer::HaveNothing;        
649     } else {
650         if (m_player->inMediaDocument()) {
651             // Something went wrong in the loading of media within a standalone file. 
652             // This can occur with chained ref movies that eventually resolve to a
653             // file we don't support.
654             sawUnsupportedTracks();
655             return;
656         }
657
658         float loaded = maxTimeLoaded();
659         if (!loaded)
660             m_readyState = MediaPlayer::HaveNothing;
661
662         if (!m_enabledTrackCount)
663             m_networkState = MediaPlayer::FormatError;
664         else {
665             // FIXME: We should differentiate between load/network errors and decode errors <rdar://problem/5605692>
666             if (loaded > 0)
667                 m_networkState = MediaPlayer::DecodeError;
668             else
669                 m_readyState = MediaPlayer::HaveNothing;
670         }
671     }
672
673     if (isReadyForRendering() && !hasSetUpVideoRendering())
674         setUpVideoRendering();
675
676     if (seeking())
677         m_readyState = MediaPlayer::HaveNothing;
678     
679     if (m_networkState != oldNetworkState)
680         m_player->networkStateChanged();
681     if (m_readyState != oldReadyState)
682         m_player->readyStateChanged();
683 }
684
685 bool MediaPlayerPrivateQuickTimeVisualContext::isReadyForRendering() const
686 {
687     return m_readyState >= MediaPlayer::HaveMetadata && m_player->visible();
688 }
689
690 void MediaPlayerPrivateQuickTimeVisualContext::sawUnsupportedTracks()
691 {
692     m_movie->setDisabled(true);
693     m_hasUnsupportedTracks = true;
694     m_player->mediaPlayerClient()->mediaPlayerSawUnsupportedTracks(m_player);
695 }
696
697 void MediaPlayerPrivateQuickTimeVisualContext::didEnd()
698 {
699     if (m_hasUnsupportedTracks)
700         return;
701
702     m_startedPlaying = false;
703
704     updateStates();
705     m_player->timeChanged();
706 }
707
708 void MediaPlayerPrivateQuickTimeVisualContext::setSize(const IntSize& size) 
709
710     if (m_hasUnsupportedTracks || !m_movie || m_size == size)
711         return;
712     m_size = size;
713 }
714
715 void MediaPlayerPrivateQuickTimeVisualContext::setVisible(bool visible)
716 {
717     if (m_hasUnsupportedTracks || !m_movie || m_visible == visible)
718         return;
719
720     m_visible = visible;
721     if (m_visible) {
722         if (isReadyForRendering())
723             setUpVideoRendering();
724     } else
725         tearDownVideoRendering();
726 }
727
728 void MediaPlayerPrivateQuickTimeVisualContext::paint(GraphicsContext* p, const IntRect& r)
729 {
730     MediaRenderingMode currentMode = currentRenderingMode();
731  
732     if (currentMode == MediaRenderingNone)
733         return;
734
735     if (currentMode == MediaRenderingSoftwareRenderer && !m_visualContext)
736         return;
737
738     QTPixelBuffer buffer = m_visualContext->imageForTime(0);
739     if (buffer.pixelBufferRef()) {
740 #if USE(ACCELERATED_COMPOSITING)
741         if (m_qtVideoLayer) {
742             // We are probably being asked to render the video into a canvas, but 
743             // there's a good chance the QTPixelBuffer is not ARGB and thus can't be
744             // drawn using CG.  If so, fire up an ICMDecompressionSession and convert 
745             // the current frame into something which can be rendered by CG.
746             if (!buffer.pixelFormatIs32ARGB() && !buffer.pixelFormatIs32BGRA()) {
747                 // The decompression session will only decompress a specific pixelFormat 
748                 // at a specific width and height; if these differ, the session must be
749                 // recreated with the new parameters.
750                 if (!m_decompressionSession || !m_decompressionSession->canDecompress(buffer))
751                     m_decompressionSession = QTDecompressionSession::create(buffer.pixelFormatType(), buffer.width(), buffer.height());
752                 buffer = m_decompressionSession->decompress(buffer);
753             }
754         }
755 #endif
756         CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
757         
758         CGContextRef context = p->platformContext();
759         CGContextSaveGState(context);
760         CGContextTranslateCTM(context, r.x(), r.y());
761         CGContextTranslateCTM(context, 0, r.height());
762         CGContextScaleCTM(context, 1, -1);
763         CGContextDrawImage(context, CGRectMake(0, 0, r.width(), r.height()), image);
764         CGContextRestoreGState(context);
765
766         CGImageRelease(image);
767     }
768     paintCompleted(*p, r);
769 }
770
771 void MediaPlayerPrivateQuickTimeVisualContext::paintCompleted(GraphicsContext& context, const IntRect& rect)
772 {
773     m_newFrameAvailable = false;
774 }
775
776 void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::retrieveCurrentImageProc(void* refcon)
777 {
778     static_cast<MediaPlayerPrivateQuickTimeVisualContext*>(refcon)->retrieveCurrentImage();
779 }
780
781 void MediaPlayerPrivateQuickTimeVisualContext::VisualContextClient::imageAvailableForTime(const QTCVTimeStamp* timeStamp)
782 {
783     // This call may come in on another thread, so marshall to the main thread first:
784     callOnMainThread(&retrieveCurrentImageProc, m_parent);
785
786     // callOnMainThread must be paired with cancelCallOnMainThread in the destructor,
787     // in case this object is deleted before the main thread request is handled.
788 }
789
790 void MediaPlayerPrivateQuickTimeVisualContext::visualContextTimerFired(Timer<MediaPlayerPrivateQuickTimeVisualContext>*)
791 {
792     if (m_visualContext && m_visualContext->isImageAvailableForTime(0))
793         retrieveCurrentImage();
794 }
795
796 static CFDictionaryRef QTCFDictionaryCreateWithDataCallback(CFAllocatorRef allocator, const UInt8* bytes, CFIndex length)
797 {
798     RetainPtr<CFDataRef> data(AdoptCF, CFDataCreateWithBytesNoCopy(allocator, bytes, length, kCFAllocatorNull));
799     if (!data)
800         return 0;
801
802     return reinterpret_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(allocator, data.get(), kCFPropertyListImmutable, 0));
803 }
804
805 static CGImageRef CreateCGImageFromPixelBuffer(QTPixelBuffer buffer)
806 {
807 #if USE(ACCELERATED_COMPOSITING)
808     CGDataProviderRef provider = 0;
809     CGColorSpaceRef colorSpace = 0;
810     CGImageRef image = 0;
811
812     size_t bitsPerComponent = 0;
813     size_t bitsPerPixel = 0;
814     CGImageAlphaInfo alphaInfo = kCGImageAlphaNone;
815         
816     if (buffer.pixelFormatIs32BGRA()) {
817         bitsPerComponent = 8;
818         bitsPerPixel = 32;
819         alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Little);
820     } else if (buffer.pixelFormatIs32ARGB()) {
821         bitsPerComponent = 8;
822         bitsPerPixel = 32;
823         alphaInfo = (CGImageAlphaInfo)(kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big);
824     } else {
825         // All other pixel formats are currently unsupported:
826         ASSERT_NOT_REACHED();
827     }
828
829     CGDataProviderDirectAccessCallbacks callbacks = {
830         &QTPixelBuffer::dataProviderGetBytePointerCallback,
831         &QTPixelBuffer::dataProviderReleaseBytePointerCallback,
832         &QTPixelBuffer::dataProviderGetBytesAtPositionCallback,
833         &QTPixelBuffer::dataProviderReleaseInfoCallback,
834     };
835     
836     // Colorspace should be device, so that Quartz does not have to do an extra render.
837     colorSpace = CGColorSpaceCreateDeviceRGB();
838     require(colorSpace, Bail);
839             
840     provider = CGDataProviderCreateDirectAccess(buffer.pixelBufferRef(), buffer.dataSize(), &callbacks);
841     require(provider, Bail);
842
843     // CGDataProvider does not retain the buffer, but it will release it later, so do an extra retain here:
844     QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
845         
846     image = CGImageCreate(buffer.width(), buffer.height(), bitsPerComponent, bitsPerPixel, buffer.bytesPerRow(), colorSpace, alphaInfo, provider, 0, false, kCGRenderingIntentDefault);
847  
848 Bail:
849     // Once the image is created we can release our reference to the provider and the colorspace, they are retained by the image
850     if (provider)
851         CGDataProviderRelease(provider);
852     if (colorSpace)
853         CGColorSpaceRelease(colorSpace);
854  
855     return image;
856 #else
857     return 0;
858 #endif
859 }
860
861
862 void MediaPlayerPrivateQuickTimeVisualContext::retrieveCurrentImage()
863 {
864     if (!m_visualContext)
865         return;
866
867 #if USE(ACCELERATED_COMPOSITING)
868     if (m_qtVideoLayer) {
869
870         QTPixelBuffer buffer = m_visualContext->imageForTime(0);
871         if (!buffer.pixelBufferRef())
872             return;
873
874         PlatformCALayer* layer = m_qtVideoLayer.get();
875
876         if (!buffer.lockBaseAddress()) {
877             if (requiredDllsAvailable()) {
878                 if (!m_imageQueue) {
879                     m_imageQueue = adoptPtr(new WKCAImageQueue(buffer.width(), buffer.height(), 30));
880                     m_imageQueue->setFlags(WKCAImageQueue::Fill, WKCAImageQueue::Fill);
881                     layer->setContents(m_imageQueue->get());
882                 }
883
884                 // Debug QuickTime links against a non-Debug version of CoreFoundation, so the
885                 // CFDictionary attached to the CVPixelBuffer cannot be directly passed on into the
886                 // CAImageQueue without being converted to a non-Debug CFDictionary.  Additionally,
887                 // old versions of QuickTime used a non-AAS CoreFoundation, so the types are not 
888                 // interchangable even in the release case.
889                 RetainPtr<CFDictionaryRef> attachments(AdoptCF, QTCFDictionaryCreateCopyWithDataCallback(kCFAllocatorDefault, buffer.attachments(), &QTCFDictionaryCreateWithDataCallback));
890                 CFTimeInterval imageTime = QTMovieVisualContext::currentHostTime();
891
892                 m_imageQueue->collect();
893
894                 uint64_t imageId = m_imageQueue->registerPixelBuffer(buffer.baseAddress(), buffer.dataSize(), buffer.bytesPerRow(), buffer.width(), buffer.height(), buffer.pixelFormatType(), attachments.get(), 0);
895
896                 if (m_imageQueue->insertImage(imageTime, WKCAImageQueue::Buffer, imageId, WKCAImageQueue::Opaque | WKCAImageQueue::Flush, &QTPixelBuffer::imageQueueReleaseCallback, buffer.pixelBufferRef())) {
897                     // Retain the buffer one extra time so it doesn't dissappear before CAImageQueue decides to release it:
898                     QTPixelBuffer::retainCallback(buffer.pixelBufferRef());
899                 }
900
901             } else {
902                 CGImageRef image = CreateCGImageFromPixelBuffer(buffer);
903                 layer->setContents(image);
904                 CGImageRelease(image);
905             }
906
907             buffer.unlockBaseAddress();
908             layer->setNeedsCommit();
909         }
910     } else
911 #endif
912         m_player->repaint();
913
914     m_visualContext->task();
915 }
916
917 static HashSet<String> mimeTypeCache()
918 {
919     DEFINE_STATIC_LOCAL(HashSet<String>, typeCache, ());
920     static bool typeListInitialized = false;
921
922     if (!typeListInitialized) {
923         unsigned count = QTMovie::countSupportedTypes();
924         for (unsigned n = 0; n < count; n++) {
925             const UChar* character;
926             unsigned len;
927             QTMovie::getSupportedType(n, character, len);
928             if (len)
929                 typeCache.add(String(character, len));
930         }
931
932         typeListInitialized = true;
933     }
934     
935     return typeCache;
936 }
937
938 static CFStringRef createVersionStringFromModuleName(LPCWSTR moduleName)
939 {
940     HMODULE module = GetModuleHandleW(moduleName);
941     if (!module) 
942         return 0;
943
944     wchar_t filePath[MAX_PATH] = {0};
945     if (!GetModuleFileNameW(module, filePath, MAX_PATH)) 
946         return 0;
947
948     DWORD versionInfoSize = GetFileVersionInfoSizeW(filePath, 0);
949     if (!versionInfoSize)
950         return 0;
951
952     CFStringRef versionString = 0;
953     void* versionInfo = calloc(versionInfoSize, sizeof(char));
954     if (GetFileVersionInfo(filePath, 0, versionInfoSize, versionInfo)) {
955         VS_FIXEDFILEINFO* fileInfo = 0;
956         UINT fileInfoLength = 0;
957
958         if (VerQueryValueW(versionInfo, L"\\", reinterpret_cast<LPVOID*>(&fileInfo), &fileInfoLength)) {
959             versionString = CFStringCreateWithFormat(kCFAllocatorDefault, 0, CFSTR("%d.%d.%d.%d"), 
960                 HIWORD(fileInfo->dwFileVersionMS), LOWORD(fileInfo->dwFileVersionMS), 
961                 HIWORD(fileInfo->dwFileVersionLS), LOWORD(fileInfo->dwFileVersionLS));
962         }
963     }
964     free(versionInfo);
965
966     return versionString;
967 }
968
969 static bool requiredDllsAvailable() 
970 {
971     static bool s_prerequisitesChecked = false;
972     static bool s_prerequisitesSatisfied;
973     static const CFStringRef kMinQuartzCoreVersion = CFSTR("1.0.42.0");
974     static const CFStringRef kMinCoreVideoVersion = CFSTR("1.0.1.0");
975
976     if (s_prerequisitesChecked)
977         return s_prerequisitesSatisfied;
978     s_prerequisitesChecked = true;
979     s_prerequisitesSatisfied = false;
980
981     CFStringRef quartzCoreString = createVersionStringFromModuleName(L"QuartzCore");
982     if (!quartzCoreString)
983         quartzCoreString = createVersionStringFromModuleName(L"QuartzCore_debug");
984
985     CFStringRef coreVideoString = createVersionStringFromModuleName(L"CoreVideo");
986     if (!coreVideoString)
987         coreVideoString = createVersionStringFromModuleName(L"CoreVideo_debug");
988
989     s_prerequisitesSatisfied = (quartzCoreString && coreVideoString
990         && CFStringCompare(quartzCoreString, kMinQuartzCoreVersion, kCFCompareNumerically) != kCFCompareLessThan 
991         && CFStringCompare(coreVideoString, kMinCoreVideoVersion, kCFCompareNumerically) != kCFCompareLessThan);
992
993     if (quartzCoreString)
994         CFRelease(quartzCoreString);
995     if (coreVideoString)
996         CFRelease(coreVideoString);
997
998     return s_prerequisitesSatisfied;
999 }
1000
1001 void MediaPlayerPrivateQuickTimeVisualContext::getSupportedTypes(HashSet<String>& types)
1002 {
1003     types = mimeTypeCache();
1004
1005
1006 bool MediaPlayerPrivateQuickTimeVisualContext::isAvailable()
1007 {
1008     return QTMovie::initializeQuickTime();
1009 }
1010
1011 MediaPlayer::SupportsType MediaPlayerPrivateQuickTimeVisualContext::supportsType(const String& type, const String& codecs)
1012 {
1013     // only return "IsSupported" if there is no codecs parameter for now as there is no way to ask QT if it supports an
1014     //  extended MIME type
1015     return mimeTypeCache().contains(type) ? (codecs.isEmpty() ? MediaPlayer::MayBeSupported : MediaPlayer::IsSupported) : MediaPlayer::IsNotSupported;
1016 }
1017
1018 void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieEnded(QTMovie* movie)
1019 {
1020     if (m_parent->m_hasUnsupportedTracks)
1021         return;
1022
1023     m_parent->m_visualContextTimer.stop();
1024
1025     ASSERT(m_parent->m_movie.get() == movie);
1026     m_parent->didEnd();
1027 }
1028
1029 void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieLoadStateChanged(QTMovie* movie)
1030 {
1031     if (m_parent->m_hasUnsupportedTracks)
1032         return;
1033
1034     ASSERT(m_parent->m_movie.get() == movie);
1035     m_parent->updateStates();
1036 }
1037
1038 void MediaPlayerPrivateQuickTimeVisualContext::MovieClient::movieTimeChanged(QTMovie* movie)
1039 {
1040     if (m_parent->m_hasUnsupportedTracks)
1041         return;
1042
1043     ASSERT(m_parent->m_movie.get() == movie);
1044     m_parent->updateStates();
1045     m_parent->m_player->timeChanged();
1046 }
1047
1048 bool MediaPlayerPrivateQuickTimeVisualContext::hasSingleSecurityOrigin() const
1049 {
1050     // We tell quicktime to disallow resources that come from different origins
1051     // so we all media is single origin.
1052     return true;
1053 }
1054
1055 void MediaPlayerPrivateQuickTimeVisualContext::setPreload(MediaPlayer::Preload preload)
1056 {
1057     m_preload = preload;
1058     if (m_delayingLoad && m_preload != MediaPlayer::None)
1059         resumeLoad();
1060 }
1061
1062 float MediaPlayerPrivateQuickTimeVisualContext::mediaTimeForTimeValue(float timeValue) const
1063 {
1064     long timeScale;
1065     if (m_readyState < MediaPlayer::HaveMetadata || !(timeScale = m_movie->timeScale()))
1066         return timeValue;
1067
1068     long mediaTimeValue = lroundf(timeValue * timeScale);
1069     return static_cast<float>(mediaTimeValue) / timeScale;
1070 }
1071
1072 MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::currentRenderingMode() const
1073 {
1074     if (!m_movie)
1075         return MediaRenderingNone;
1076
1077 #if USE(ACCELERATED_COMPOSITING)
1078     if (m_qtVideoLayer)
1079         return MediaRenderingMovieLayer;
1080 #endif
1081
1082     return m_visualContext ? MediaRenderingSoftwareRenderer : MediaRenderingNone;
1083 }
1084
1085 MediaPlayerPrivateQuickTimeVisualContext::MediaRenderingMode MediaPlayerPrivateQuickTimeVisualContext::preferredRenderingMode() const
1086 {
1087     if (!m_player->frameView() || !m_movie)
1088         return MediaRenderingNone;
1089
1090 #if USE(ACCELERATED_COMPOSITING)
1091     if (supportsAcceleratedRendering() && m_player->mediaPlayerClient()->mediaPlayerRenderingCanBeAccelerated(m_player))
1092         return MediaRenderingMovieLayer;
1093 #endif
1094
1095     return MediaRenderingSoftwareRenderer;
1096 }
1097
1098 void MediaPlayerPrivateQuickTimeVisualContext::setUpVideoRendering()
1099 {
1100     MediaRenderingMode currentMode = currentRenderingMode();
1101     MediaRenderingMode preferredMode = preferredRenderingMode();
1102
1103 #if !USE(ACCELERATED_COMPOSITING)
1104     ASSERT(preferredMode != MediaRenderingMovieLayer);
1105 #endif
1106
1107     if (currentMode == preferredMode && currentMode != MediaRenderingNone)
1108         return;
1109
1110     if (currentMode != MediaRenderingNone)  
1111         tearDownVideoRendering();
1112
1113     if (preferredMode == MediaRenderingMovieLayer)
1114         createLayerForMovie();
1115
1116 #if USE(ACCELERATED_COMPOSITING)
1117     if (currentMode == MediaRenderingMovieLayer || preferredMode == MediaRenderingMovieLayer)
1118         m_player->mediaPlayerClient()->mediaPlayerRenderingModeChanged(m_player);
1119 #endif
1120
1121     QTPixelBuffer::Type contextType = requiredDllsAvailable() && preferredMode == MediaRenderingMovieLayer ? QTPixelBuffer::ConfigureForCAImageQueue : QTPixelBuffer::ConfigureForCGImage;
1122     m_visualContext = QTMovieVisualContext::create(m_visualContextClient.get(), contextType);
1123     m_visualContext->setMovie(m_movie.get());
1124 }
1125
1126 void MediaPlayerPrivateQuickTimeVisualContext::tearDownVideoRendering()
1127 {
1128 #if USE(ACCELERATED_COMPOSITING)
1129     if (m_qtVideoLayer)
1130         destroyLayerForMovie();
1131 #endif
1132
1133     m_visualContext = 0;
1134 }
1135
1136 bool MediaPlayerPrivateQuickTimeVisualContext::hasSetUpVideoRendering() const
1137 {
1138 #if USE(ACCELERATED_COMPOSITING)
1139     return m_qtVideoLayer || (currentRenderingMode() != MediaRenderingMovieLayer && m_visualContext);
1140 #else
1141     return true;
1142 #endif
1143 }
1144
1145 void MediaPlayerPrivateQuickTimeVisualContext::retrieveAndResetMovieTransform()
1146 {
1147 #if USE(ACCELERATED_COMPOSITING)
1148     // First things first, reset the total movie transform so that
1149     // we can bail out early:
1150     m_movieTransform = CGAffineTransformIdentity;
1151
1152     if (!m_movie || !m_movie->hasVideo())
1153         return;
1154
1155     // This trick will only work on movies with a single video track,
1156     // so bail out early if the video contains more than one (or zero)
1157     // video tracks.
1158     QTTrackArray videoTracks = m_movie->videoTracks();
1159     if (videoTracks.size() != 1)
1160         return;
1161
1162     QTTrack* track = videoTracks[0].get();
1163     ASSERT(track);
1164
1165     CGAffineTransform movieTransform = m_movie->getTransform();
1166     if (!CGAffineTransformEqualToTransform(movieTransform, CGAffineTransformIdentity))
1167         m_movie->resetTransform();
1168
1169     CGAffineTransform trackTransform = track->getTransform();
1170     if (!CGAffineTransformEqualToTransform(trackTransform, CGAffineTransformIdentity))
1171         track->resetTransform();
1172
1173     // Multiply the two transforms together, taking care to 
1174     // do so in the correct order, track * movie = final:
1175     m_movieTransform = CGAffineTransformConcat(trackTransform, movieTransform);
1176 #endif
1177 }
1178
1179 void MediaPlayerPrivateQuickTimeVisualContext::createLayerForMovie()
1180 {
1181 #if USE(ACCELERATED_COMPOSITING)
1182     ASSERT(supportsAcceleratedRendering());
1183
1184     if (!m_movie || m_qtVideoLayer)
1185         return;
1186
1187     // Create a PlatformCALayer which will transform the contents of the video layer
1188     // which is in m_qtVideoLayer.
1189     m_transformLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, m_layerClient.get());
1190     if (!m_transformLayer)
1191         return;
1192
1193     // Mark the layer as anchored in the top left.
1194     m_transformLayer->setAnchorPoint(FloatPoint3D());
1195
1196     m_qtVideoLayer = PlatformCALayer::create(PlatformCALayer::LayerTypeLayer, 0);
1197     if (!m_qtVideoLayer)
1198         return;
1199
1200     if (CGAffineTransformEqualToTransform(m_movieTransform, CGAffineTransformIdentity))
1201         retrieveAndResetMovieTransform();
1202     CGAffineTransform t = m_movieTransform;
1203
1204     // Remove the translation portion of the transform, since we will always rotate about
1205     // the layer's center point.  In our limited use-case (a single video track), this is
1206     // safe:
1207     t.tx = t.ty = 0;
1208     m_qtVideoLayer->setTransform(CATransform3DMakeAffineTransform(t));
1209
1210 #ifndef NDEBUG
1211     m_qtVideoLayer->setName("Video layer");
1212 #endif
1213     m_transformLayer->appendSublayer(m_qtVideoLayer.get());
1214     m_transformLayer->setNeedsLayout();
1215     // The layer will get hooked up via RenderLayerBacking::updateGraphicsLayerConfiguration().
1216 #endif
1217
1218     // Fill the newly created layer with image data, so we're not looking at 
1219     // an empty layer until the next time a new image is available, which could
1220     // be a long time if we're paused.
1221     if (m_visualContext)
1222         retrieveCurrentImage();
1223 }
1224
1225 void MediaPlayerPrivateQuickTimeVisualContext::destroyLayerForMovie()
1226 {
1227 #if USE(ACCELERATED_COMPOSITING)
1228     if (m_qtVideoLayer) {
1229         m_qtVideoLayer->removeFromSuperlayer();
1230         m_qtVideoLayer = 0;
1231     }
1232
1233     if (m_transformLayer)
1234         m_transformLayer = 0;
1235
1236     if (m_imageQueue)
1237         m_imageQueue = nullptr;
1238 #endif
1239 }
1240
1241 #if USE(ACCELERATED_COMPOSITING)
1242 bool MediaPlayerPrivateQuickTimeVisualContext::supportsAcceleratedRendering() const
1243 {
1244     return isReadyForRendering();
1245 }
1246
1247 void MediaPlayerPrivateQuickTimeVisualContext::acceleratedRenderingStateChanged()
1248 {
1249     // Set up or change the rendering path if necessary.
1250     setUpVideoRendering();
1251 }
1252
1253 void MediaPlayerPrivateQuickTimeVisualContext::setPrivateBrowsingMode(bool privateBrowsing)
1254 {
1255     m_privateBrowsing = privateBrowsing;
1256     if (m_movie)
1257         m_movie->setPrivateBrowsingMode(m_privateBrowsing);
1258 }
1259     
1260 #endif
1261
1262
1263 }
1264
1265 #endif