Fix the build for __IPHONE_OS_VERSION_MIN_REQUIRED <= 80200 || !HAVE(AVKIT)
[WebKit-https.git] / Source / WebCore / platform / ios / WebVideoFullscreenControllerAVKit.mm
1 /*
2  * Copyright (C) 2013 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 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 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 #import "config.h"
27
28 #if PLATFORM(IOS)
29
30 #import "WebVideoFullscreenControllerAVKit.h"
31
32 #import "Logging.h"
33 #import "QuartzCoreSPI.h"
34 #import "SoftLinking.h"
35 #import "TimeRanges.h"
36 #import "WebVideoFullscreenInterfaceAVKit.h"
37 #import "WebVideoFullscreenModelVideoElement.h"
38 #import <QuartzCore/CoreAnimation.h>
39 #import <WebCore/FrameView.h>
40 #import <WebCore/HTMLVideoElement.h>
41 #import <WebCore/RenderElement.h>
42 #import <WebCore/WebCoreThreadRun.h>
43
44 SOFT_LINK_FRAMEWORK(UIKit)
45 SOFT_LINK_CLASS(UIKit, UIView)
46
47 using namespace WebCore;
48
49 #if __IPHONE_OS_VERSION_MIN_REQUIRED <= 80200 || !HAVE(AVKIT)
50
51 @implementation WebVideoFullscreenController
52 - (void)setVideoElement:(WebCore::HTMLVideoElement*)videoElement
53 {
54     UNUSED_PARAM(videoElement);
55 }
56
57 - (WebCore::HTMLVideoElement*)videoElement
58 {
59     return nullptr;
60 }
61
62 - (void)enterFullscreen:(UIView *)view mode:(WebCore::HTMLMediaElementEnums::VideoFullscreenMode)mode
63 {
64     UNUSED_PARAM(view);
65     UNUSED_PARAM(mode);
66 }
67
68 - (void)requestHideAndExitFullscreen
69 {
70 }
71
72 - (void)exitFullscreen
73 {
74 }
75 @end
76
77 #else
78
79 static IntRect elementRectInWindow(HTMLVideoElement* videoElement)
80 {
81     if (!videoElement || !videoElement->renderer() || !videoElement->document().view())
82         return IntRect();
83     
84     return videoElement->document().view()->convertToContainingWindow(videoElement->renderer()->absoluteBoundingBoxRect());
85 }
86
87 class WebVideoFullscreenControllerContext;
88
89 @interface WebVideoFullscreenController (delegate)
90 -(void)didFinishFullscreen:(WebVideoFullscreenControllerContext*)context;
91 @end
92
93 class WebVideoFullscreenControllerContext final
94     : private WebVideoFullscreenInterface
95     , private WebVideoFullscreenModel
96     , private WebVideoFullscreenChangeObserver
97     , public ThreadSafeRefCounted<WebVideoFullscreenControllerContext> {
98
99 public:
100     static Ref<WebVideoFullscreenControllerContext> create()
101     {
102         return adoptRef(*new WebVideoFullscreenControllerContext);
103     }
104     
105     void setController(WebVideoFullscreenController* controller) { m_controller = controller; }
106     void setUpFullscreen(HTMLVideoElement&, UIView *, HTMLMediaElementEnums::VideoFullscreenMode);
107     void exitFullscreen();
108     void requestHideAndExitFullscreen();
109     void invalidate();
110
111 private:
112     WebVideoFullscreenControllerContext() { }
113
114     // WebVideoFullscreenChangeObserver
115     virtual void didSetupFullscreen() override;
116     virtual void didEnterFullscreen() override { }
117     virtual void didExitFullscreen() override;
118     virtual void didCleanupFullscreen() override;
119     virtual void fullscreenMayReturnToInline() override;
120     
121     // WebVideoFullscreenInterface
122     virtual void resetMediaState() override;
123     virtual void setDuration(double) override;
124     virtual void setCurrentTime(double currentTime, double anchorTime) override;
125     virtual void setBufferedTime(double) override;
126     virtual void setRate(bool isPlaying, float playbackRate) override;
127     virtual void setVideoDimensions(bool hasVideo, float width, float height) override;
128     virtual void setSeekableRanges(const TimeRanges&) override;
129     virtual void setCanPlayFastReverse(bool) override;
130     virtual void setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex) override;
131     virtual void setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex) override;
132     virtual void setExternalPlayback(bool enabled, ExternalPlaybackTargetType, String localizedDeviceName) override;
133     
134     // WebVideoFullscreenModel
135     virtual void play() override;
136     virtual void pause() override;
137     virtual void togglePlayState() override;
138     virtual void beginScrubbing() override;
139     virtual void endScrubbing() override;
140     virtual void seekToTime(double time) override;
141     virtual void fastSeek(double time) override;
142     virtual void beginScanningForward() override;
143     virtual void beginScanningBackward() override;
144     virtual void endScanning() override;
145     virtual void requestExitFullscreen() override;
146     virtual void setVideoLayerFrame(FloatRect) override;
147     virtual void setVideoLayerGravity(WebVideoFullscreenModel::VideoGravity) override;
148     virtual void selectAudioMediaOption(uint64_t index) override;
149     virtual void selectLegibleMediaOption(uint64_t index) override;
150     virtual void fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode) override;
151     
152     RefPtr<WebVideoFullscreenInterfaceAVKit> m_interface;
153     RefPtr<WebVideoFullscreenModelVideoElement> m_model;
154     RefPtr<HTMLVideoElement> m_videoElement;
155     RetainPtr<UIView> m_videoFullscreenView;
156     RetainPtr<WebVideoFullscreenController> m_controller;
157 };
158
159 #pragma mark WebVideoFullscreenChangeObserver
160
161 void WebVideoFullscreenControllerContext::didSetupFullscreen()
162 {
163     ASSERT(isUIThread());
164     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
165     RetainPtr<CALayer> videoFullscreenLayer = [m_videoFullscreenView layer];
166     WebThreadRun([strongThis, this, videoFullscreenLayer] {
167         [videoFullscreenLayer setBackgroundColor:cachedCGColor(WebCore::Color::transparent, WebCore::ColorSpaceDeviceRGB)];
168         m_model->setVideoFullscreenLayer(videoFullscreenLayer.get());
169         dispatch_async(dispatch_get_main_queue(), [strongThis, this] {
170             m_interface->enterFullscreen();
171         });
172     });
173 }
174
175 void WebVideoFullscreenControllerContext::didExitFullscreen()
176 {
177     ASSERT(isUIThread());
178     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
179     WebThreadRun([strongThis, this] {
180         m_model->setVideoFullscreenLayer(nil);
181         dispatch_async(dispatch_get_main_queue(), [strongThis, this] {
182             m_interface->cleanupFullscreen();
183         });
184     });
185 }
186
187 void WebVideoFullscreenControllerContext::didCleanupFullscreen()
188 {
189     ASSERT(isUIThread());
190     m_interface->setWebVideoFullscreenModel(nullptr);
191     m_interface->setWebVideoFullscreenChangeObserver(nullptr);
192     m_interface = nullptr;
193     m_videoFullscreenView = nil;
194     
195     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
196     WebThreadRun([strongThis, this] {
197         m_model->setVideoFullscreenLayer(nil);
198         m_model->setWebVideoFullscreenInterface(nullptr);
199         m_model->setVideoElement(nullptr);
200         m_model = nullptr;
201         m_videoElement = nullptr;
202         
203         [m_controller didFinishFullscreen:this];
204     });
205 }
206
207 void WebVideoFullscreenControllerContext::fullscreenMayReturnToInline()
208 {
209     ASSERT(isUIThread());
210     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
211     WebThreadRun([strongThis, this] {
212         IntRect clientRect = elementRectInWindow(m_videoElement.get());
213         dispatch_async(dispatch_get_main_queue(), [strongThis, this, clientRect] {
214             m_interface->preparedToReturnToInline(true, clientRect);
215         });
216     });
217 }
218
219 #pragma mark WebVideoFullscreenInterface
220
221 void WebVideoFullscreenControllerContext::resetMediaState()
222 {
223     ASSERT(WebThreadIsCurrent() || isMainThread());
224     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
225     dispatch_async(dispatch_get_main_queue(), [strongThis, this] {
226         if (m_interface)
227             m_interface->resetMediaState();
228     });
229 }
230
231 void WebVideoFullscreenControllerContext::setDuration(double duration)
232 {
233     ASSERT(WebThreadIsCurrent());
234     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
235     dispatch_async(dispatch_get_main_queue(), [strongThis, this, duration] {
236         if (m_interface)
237             m_interface->setDuration(duration);
238     });
239 }
240
241 void WebVideoFullscreenControllerContext::setCurrentTime(double currentTime, double anchorTime)
242 {
243     ASSERT(WebThreadIsCurrent());
244     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
245     dispatch_async(dispatch_get_main_queue(), [strongThis, this, currentTime, anchorTime] {
246         if (m_interface)
247             m_interface->setCurrentTime(currentTime, anchorTime);
248     });
249 }
250
251 void WebVideoFullscreenControllerContext::setBufferedTime(double bufferedTime)
252 {
253     ASSERT(WebThreadIsCurrent());
254     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
255     dispatch_async(dispatch_get_main_queue(), [strongThis, this, bufferedTime] {
256         if (m_interface)
257             m_interface->setBufferedTime(bufferedTime);
258     });
259 }
260
261 void WebVideoFullscreenControllerContext::setRate(bool isPlaying, float playbackRate)
262 {
263     ASSERT(WebThreadIsCurrent());
264     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
265     dispatch_async(dispatch_get_main_queue(), [strongThis, this, isPlaying, playbackRate] {
266         if (m_interface)
267             m_interface->setRate(isPlaying, playbackRate);
268     });
269 }
270
271 void WebVideoFullscreenControllerContext::setVideoDimensions(bool hasVideo, float width, float height)
272 {
273     ASSERT(WebThreadIsCurrent());
274     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
275     dispatch_async(dispatch_get_main_queue(), [strongThis, this, hasVideo, width, height] {
276         if (m_interface)
277             m_interface->setVideoDimensions(hasVideo, width, height);
278     });
279 }
280
281 void WebVideoFullscreenControllerContext::setSeekableRanges(const TimeRanges& timeRanges)
282 {
283     ASSERT(WebThreadIsCurrent());
284     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
285     const PlatformTimeRanges& platformTimeRanges = timeRanges.ranges();
286     dispatch_async(dispatch_get_main_queue(), [strongThis, this, platformTimeRanges] {
287         if (m_interface)
288             m_interface->setSeekableRanges(TimeRanges::create(platformTimeRanges));
289     });
290 }
291
292 void WebVideoFullscreenControllerContext::setCanPlayFastReverse(bool canPlayFastReverse)
293 {
294     ASSERT(WebThreadIsCurrent());
295     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
296     dispatch_async(dispatch_get_main_queue(), [strongThis, this, canPlayFastReverse] {
297         if (m_interface)
298             m_interface->setCanPlayFastReverse(canPlayFastReverse);
299     });
300 }
301
302 void WebVideoFullscreenControllerContext::setAudioMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
303 {
304     ASSERT(WebThreadIsCurrent());
305     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
306
307     RetainPtr<NSMutableArray> optionsArray = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
308     for (auto& name : options)
309         [optionsArray addObject:name];
310     
311     dispatch_async(dispatch_get_main_queue(), [strongThis, this, optionsArray, selectedIndex] {
312         Vector<String> options;
313         for (NSString *name : optionsArray.get())
314             options.append(name);
315         
316         if (m_interface)
317             m_interface->setAudioMediaSelectionOptions(options, selectedIndex);
318     });
319 }
320
321 void WebVideoFullscreenControllerContext::setLegibleMediaSelectionOptions(const Vector<String>& options, uint64_t selectedIndex)
322 {
323     ASSERT(WebThreadIsCurrent());
324     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
325     
326     RetainPtr<NSMutableArray> optionsArray = adoptNS([[NSMutableArray alloc] initWithCapacity:options.size()]);
327     for (auto& name : options)
328         [optionsArray addObject:name];
329     
330     dispatch_async(dispatch_get_main_queue(), [strongThis, this, optionsArray, selectedIndex] {
331         Vector<String> options;
332         for (NSString *name : optionsArray.get())
333             options.append(name);
334         
335         if (m_interface)
336             m_interface->setLegibleMediaSelectionOptions(options, selectedIndex);
337     });
338 }
339
340 void WebVideoFullscreenControllerContext::setExternalPlayback(bool enabled, ExternalPlaybackTargetType type, String localizedDeviceName)
341 {
342     ASSERT(WebThreadIsCurrent());
343     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
344     StringCapture capturedLocalizedDeviceName(localizedDeviceName);
345     dispatch_async(dispatch_get_main_queue(), [strongThis, this, enabled, type, capturedLocalizedDeviceName] {
346         if (m_interface)
347             m_interface->setExternalPlayback(enabled, type, capturedLocalizedDeviceName.string());
348     });
349 }
350
351 #pragma mark WebVideoFullscreenModel
352
353 void WebVideoFullscreenControllerContext::play()
354 {
355     ASSERT(isUIThread());
356     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
357     WebThreadRun([strongThis, this] {
358         if (m_model)
359             m_model->play();
360     });
361 }
362
363 void WebVideoFullscreenControllerContext::pause()
364 {
365     ASSERT(isUIThread());
366     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
367     WebThreadRun([strongThis, this] {
368         if (m_model)
369             m_model->pause();
370     });
371 }
372
373 void WebVideoFullscreenControllerContext::togglePlayState()
374 {
375     ASSERT(isUIThread());
376     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
377     WebThreadRun([strongThis, this] {
378         if (m_model)
379             m_model->togglePlayState();
380     });
381 }
382
383 void WebVideoFullscreenControllerContext::beginScrubbing()
384 {
385     ASSERT(isUIThread());
386     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
387     WebThreadRun([strongThis, this] {
388         if (m_model)
389             m_model->beginScrubbing();
390     });
391 }
392
393 void WebVideoFullscreenControllerContext::endScrubbing()
394 {
395     ASSERT(isUIThread());
396     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
397     WebThreadRun([strongThis, this] {
398         if (m_model)
399             m_model->endScrubbing();
400     });
401 }
402
403 void WebVideoFullscreenControllerContext::seekToTime(double time)
404 {
405     ASSERT(isUIThread());
406     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
407     WebThreadRun([strongThis, this, time] {
408         if (m_model)
409             m_model->seekToTime(time);
410     });
411 }
412
413 void WebVideoFullscreenControllerContext::fastSeek(double time)
414 {
415     ASSERT(isUIThread());
416     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
417     WebThreadRun([strongThis, this, time] {
418         if (m_model)
419             m_model->fastSeek(time);
420     });
421 }
422
423 void WebVideoFullscreenControllerContext::beginScanningForward()
424 {
425     ASSERT(isUIThread());
426     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
427     WebThreadRun([strongThis, this] {
428         if (m_model)
429             m_model->beginScanningForward();
430     });
431 }
432
433 void WebVideoFullscreenControllerContext::beginScanningBackward()
434 {
435     ASSERT(isUIThread());
436     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
437     WebThreadRun([strongThis, this] {
438         if (m_model)
439             m_model->beginScanningBackward();
440     });
441 }
442
443 void WebVideoFullscreenControllerContext::endScanning()
444 {
445     ASSERT(isUIThread());
446     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
447     WebThreadRun([strongThis, this] {
448         if (m_model)
449             m_model->endScanning();
450     });
451 }
452
453 void WebVideoFullscreenControllerContext::requestExitFullscreen()
454 {
455     ASSERT(isUIThread());
456     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
457     WebThreadRun([strongThis, this] {
458         if (m_model)
459             m_model->requestExitFullscreen();
460     });
461 }
462
463 void WebVideoFullscreenControllerContext::setVideoLayerFrame(FloatRect frame)
464 {
465     ASSERT(isUIThread());
466     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
467     RetainPtr<CALayer> videoFullscreenLayer = [m_videoFullscreenView layer];
468     
469     [videoFullscreenLayer setSublayerTransform:[videoFullscreenLayer transform]];
470
471     dispatch_async(dispatch_get_main_queue(), ^{
472         WebThreadRun([strongThis, this, frame, videoFullscreenLayer] {
473             [CATransaction begin];
474             [CATransaction setDisableActions:YES];
475             [CATransaction setAnimationDuration:0];
476             
477             [videoFullscreenLayer setSublayerTransform:CATransform3DIdentity];
478             
479             if (m_model)
480                 m_model->setVideoLayerFrame(frame);
481             [CATransaction commit];
482         });
483     });
484 }
485
486 void WebVideoFullscreenControllerContext::setVideoLayerGravity(WebVideoFullscreenModel::VideoGravity videoGravity)
487 {
488     ASSERT(isUIThread());
489     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
490     WebThreadRun([strongThis, this, videoGravity] {
491         if (m_model)
492             m_model->setVideoLayerGravity(videoGravity);
493     });
494 }
495
496 void WebVideoFullscreenControllerContext::selectAudioMediaOption(uint64_t index)
497 {
498     ASSERT(isUIThread());
499     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
500     WebThreadRun([strongThis, this, index] {
501         if (m_model)
502             m_model->selectAudioMediaOption(index);
503     });
504 }
505
506 void WebVideoFullscreenControllerContext::selectLegibleMediaOption(uint64_t index)
507 {
508     ASSERT(isUIThread());
509     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
510     WebThreadRun([strongThis, this, index] {
511         if (m_model)
512             m_model->selectLegibleMediaOption(index);
513     });
514 }
515
516 void WebVideoFullscreenControllerContext::fullscreenModeChanged(HTMLMediaElementEnums::VideoFullscreenMode mode)
517 {
518     ASSERT(isUIThread());
519     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
520     WebThreadRun([strongThis, this, mode] {
521         if (m_model)
522             m_model->fullscreenModeChanged(mode);
523     });
524 }
525
526 #pragma mark Other
527
528 void WebVideoFullscreenControllerContext::setUpFullscreen(HTMLVideoElement& videoElement, UIView *view, HTMLMediaElementEnums::VideoFullscreenMode mode)
529 {
530     ASSERT(isMainThread());
531     RetainPtr<UIView> viewRef = view;
532     m_videoElement = &videoElement;
533
534     m_interface = WebVideoFullscreenInterfaceAVKit::create();
535     m_interface->setWebVideoFullscreenChangeObserver(this);
536     m_interface->setWebVideoFullscreenModel(this);
537     m_videoFullscreenView = adoptNS([[getUIViewClass() alloc] init]);
538     
539     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
540     WebThreadRun([strongThis, this, viewRef, mode] {
541         m_model = WebVideoFullscreenModelVideoElement::create();
542         m_model->setWebVideoFullscreenInterface(this);
543         m_model->setVideoElement(m_videoElement.get());
544         
545         bool allowsPictureInPicture = m_videoElement->mediaSession().allowsPictureInPicture(*m_videoElement.get());
546
547         IntRect videoElementClientRect = elementRectInWindow(m_videoElement.get());
548         FloatRect videoLayerFrame = FloatRect(FloatPoint(), videoElementClientRect.size());
549         m_model->setVideoLayerFrame(videoLayerFrame);
550         
551         dispatch_async(dispatch_get_main_queue(), [strongThis, this, videoElementClientRect, viewRef, mode, allowsPictureInPicture] {
552             m_interface->setupFullscreen(*m_videoFullscreenView.get(), videoElementClientRect, viewRef.get(), mode, allowsPictureInPicture);
553         });
554     });
555 }
556
557 void WebVideoFullscreenControllerContext::exitFullscreen()
558 {
559     ASSERT(WebThreadIsCurrent() || isMainThread());
560     IntRect clientRect = elementRectInWindow(m_videoElement.get());
561     RefPtr<WebVideoFullscreenControllerContext> strongThis(this);
562     dispatch_async(dispatch_get_main_queue(), [strongThis, this, clientRect] {
563         ASSERT(isUIThread());
564         m_interface->exitFullscreen(clientRect);
565     });
566 }
567
568 void WebVideoFullscreenControllerContext::requestHideAndExitFullscreen()
569 {
570     ASSERT(isUIThread());
571     m_interface->requestHideAndExitFullscreen();
572 }
573
574 @implementation WebVideoFullscreenController {
575     RefPtr<WebVideoFullscreenControllerContext> _context;
576     RefPtr<HTMLVideoElement> _videoElement;
577 }
578
579 - (instancetype)init
580 {
581     if (!(self = [super init]))
582         return nil;
583     
584     return self;
585 }
586
587 - (void)setVideoElement:(HTMLVideoElement*)videoElement
588 {
589     _videoElement = videoElement;
590 }
591
592 - (HTMLVideoElement*)videoElement
593 {
594     return _videoElement.get();
595 }
596
597 - (void)enterFullscreen:(UIView *)view mode:(HTMLMediaElementEnums::VideoFullscreenMode)mode
598 {
599     ASSERT(isMainThread());
600     _context = WebVideoFullscreenControllerContext::create();
601     _context->setController(self);
602     _context->setUpFullscreen(*_videoElement.get(), view, mode);
603 }
604
605 - (void)exitFullscreen
606 {
607     ASSERT(WebThreadIsCurrent() || isMainThread());
608     _context->exitFullscreen();
609 }
610
611 - (void)requestHideAndExitFullscreen
612 {
613     ASSERT(isUIThread());
614     if (_context)
615         _context->requestHideAndExitFullscreen();
616 }
617
618 - (void)didFinishFullscreen:(WebVideoFullscreenControllerContext*)context
619 {
620     ASSERT(WebThreadIsCurrent());
621     ASSERT_UNUSED(context, context == _context);
622     [[self retain] autorelease]; // retain self before breaking a retain cycle.
623     _context->setController(nil);
624     _context = nullptr;
625     _videoElement = nullptr;
626 }
627
628 @end
629
630 #endif // __IPHONE_OS_VERSION_MIN_REQUIRED < 80000
631
632 #endif // PLATFORM(IOS)