Enable picture-in-picture from inline element on suspend.
[WebKit-https.git] / Source / WebCore / platform / ios / VideoFullscreenInterfaceAVKit.mm
1 /*
2  * Copyright (C) 2014, 2015 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 #import "VideoFullscreenInterfaceAVKit.h"
30
31 #if HAVE(AVKIT)
32
33 #import "GeometryUtilities.h"
34 #import "Logging.h"
35 #import "PlaybackSessionInterfaceAVKit.h"
36 #import "RuntimeApplicationChecks.h"
37 #import "TimeRanges.h"
38 #import "VideoFullscreenChangeObserver.h"
39 #import "VideoFullscreenModel.h"
40 #import "WebAVPlayerController.h"
41 #import <AVFoundation/AVTime.h>
42 #import <UIKit/UIKit.h>
43 #import <objc/message.h>
44 #import <objc/runtime.h>
45 #import <pal/spi/cocoa/AVKitSPI.h>
46 #import <wtf/RetainPtr.h>
47 #import <wtf/text/CString.h>
48 #import <wtf/text/WTFString.h>
49
50 using namespace WebCore;
51
52 // Soft-linking headers must be included last since they #define functions, constants, etc.
53 #import <pal/cf/CoreMediaSoftLink.h>
54
55 SOFT_LINK_FRAMEWORK(AVFoundation)
56 SOFT_LINK_CLASS(AVFoundation, AVPlayerLayer)
57 SOFT_LINK_CONSTANT(AVFoundation, AVLayerVideoGravityResize, NSString *)
58 SOFT_LINK_CONSTANT(AVFoundation, AVLayerVideoGravityResizeAspect, NSString *)
59 SOFT_LINK_CONSTANT(AVFoundation, AVLayerVideoGravityResizeAspectFill, NSString *)
60
61 SOFT_LINK_FRAMEWORK_OPTIONAL(AVKit)
62 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVPictureInPictureController)
63 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVPlayerViewController)
64 SOFT_LINK_CLASS_OPTIONAL(AVKit, __AVPlayerLayerView)
65
66 SOFT_LINK_FRAMEWORK(UIKit)
67 SOFT_LINK_CLASS(UIKit, UIApplication)
68 SOFT_LINK_CLASS(UIKit, UIScreen)
69 SOFT_LINK_CLASS(UIKit, UIWindow)
70 SOFT_LINK_CLASS(UIKit, UIView)
71 SOFT_LINK_CLASS(UIKit, UIViewController)
72 SOFT_LINK_CLASS(UIKit, UIColor)
73 SOFT_LINK_CONSTANT(UIKit, UITextEffectsBeneathStatusBarWindowLevel, UIWindowLevel)
74
75 @interface UIWindow ()
76 - (BOOL)_isHostedInAnotherProcess;
77 @end
78
79 @interface UIViewController ()
80 @property (nonatomic, assign, setter=_setIgnoreAppSupportedOrientations:) BOOL _ignoreAppSupportedOrientations;
81 @end
82
83 static UIColor *clearUIColor()
84 {
85     return (UIColor *)[getUIColorClass() clearColor];
86 }
87
88 #if !LOG_DISABLED
89 static const char* boolString(bool val)
90 {
91     return val ? "true" : "false";
92 }
93 #endif
94
95 static const Seconds defaultWatchdogTimerInterval { 1_s };
96
97 @class WebAVMediaSelectionOption;
98
99 @interface WebAVPlayerViewControllerDelegate : NSObject <AVPlayerViewControllerDelegate_WebKitOnly> {
100     RefPtr<VideoFullscreenInterfaceAVKit> _fullscreenInterface;
101 }
102 @property (assign) VideoFullscreenInterfaceAVKit* fullscreenInterface;
103 - (BOOL)playerViewController:(AVPlayerViewController *)playerViewController shouldExitFullScreenWithReason:(AVPlayerViewControllerExitFullScreenReason)reason;
104 @end
105
106 @implementation WebAVPlayerViewControllerDelegate
107 - (VideoFullscreenInterfaceAVKit*)fullscreenInterface
108 {
109     return _fullscreenInterface.get();
110 }
111
112 - (void)setFullscreenInterface:(VideoFullscreenInterfaceAVKit*)fullscreenInterface
113 {
114     _fullscreenInterface = fullscreenInterface;
115 }
116
117 - (void)playerViewControllerWillStartPictureInPicture:(AVPlayerViewController *)playerViewController
118 {
119     UNUSED_PARAM(playerViewController);
120     self.fullscreenInterface->willStartPictureInPicture();
121 }
122
123 - (void)playerViewControllerDidStartPictureInPicture:(AVPlayerViewController *)playerViewController
124 {
125     UNUSED_PARAM(playerViewController);
126     self.fullscreenInterface->didStartPictureInPicture();
127 }
128
129 - (void)playerViewControllerFailedToStartPictureInPicture:(AVPlayerViewController *)playerViewController withError:(NSError *)error
130 {
131     UNUSED_PARAM(playerViewController);
132     UNUSED_PARAM(error);
133     self.fullscreenInterface->failedToStartPictureInPicture();
134 }
135
136 - (void)playerViewControllerWillStopPictureInPicture:(AVPlayerViewController *)playerViewController
137 {
138     UNUSED_PARAM(playerViewController);
139     self.fullscreenInterface->willStopPictureInPicture();
140 }
141
142 - (void)playerViewControllerDidStopPictureInPicture:(AVPlayerViewController *)playerViewController
143 {
144     UNUSED_PARAM(playerViewController);
145     self.fullscreenInterface->didStopPictureInPicture();
146 }
147
148 static VideoFullscreenInterfaceAVKit::ExitFullScreenReason convertToExitFullScreenReason(AVPlayerViewControllerExitFullScreenReason reason)
149 {
150     switch (reason) {
151     case AVPlayerViewControllerExitFullScreenReasonDoneButtonTapped:
152         return VideoFullscreenInterfaceAVKit::ExitFullScreenReason::DoneButtonTapped;
153     case AVPlayerViewControllerExitFullScreenReasonFullScreenButtonTapped:
154         return VideoFullscreenInterfaceAVKit::ExitFullScreenReason::FullScreenButtonTapped;
155     case AVPlayerViewControllerExitFullScreenReasonPictureInPictureStarted:
156         return VideoFullscreenInterfaceAVKit::ExitFullScreenReason::PictureInPictureStarted;
157     case AVPlayerViewControllerExitFullScreenReasonPinchGestureHandled:
158         return VideoFullscreenInterfaceAVKit::ExitFullScreenReason::PinchGestureHandled;
159     case AVPlayerViewControllerExitFullScreenReasonRemoteControlStopEventReceived:
160         return VideoFullscreenInterfaceAVKit::ExitFullScreenReason::RemoteControlStopEventReceived;
161     }
162 }
163
164 - (BOOL)playerViewController:(AVPlayerViewController *)playerViewController shouldExitFullScreenWithReason:(AVPlayerViewControllerExitFullScreenReason)reason
165 {
166     UNUSED_PARAM(playerViewController);
167     return self.fullscreenInterface->shouldExitFullscreenWithReason(convertToExitFullScreenReason(reason));
168 }
169
170 - (void)playerViewController:(AVPlayerViewController *)playerViewController restoreUserInterfaceForPictureInPictureStopWithCompletionHandler:(void (^)(BOOL restored))completionHandler
171 {
172     UNUSED_PARAM(playerViewController);
173     self.fullscreenInterface->prepareForPictureInPictureStopWithCompletionHandler(completionHandler);
174 }
175
176 #if ENABLE(FULLSCREEN_API)
177 - (BOOL)playerViewControllerShouldStartPictureInPictureFromInlineWhenEnteringBackground:(AVPlayerViewController *)playerViewController
178 {
179     UNUSED_PARAM(playerViewController);
180     return YES;
181 }
182 #endif
183
184 @end
185
186 @interface WebAVPlayerLayer : CALayer
187 @property (nonatomic, retain) NSString *videoGravity;
188 @property (nonatomic, getter=isReadyForDisplay) BOOL readyForDisplay;
189 @property (nonatomic, assign) VideoFullscreenInterfaceAVKit* fullscreenInterface;
190 @property (nonatomic, retain) AVPlayerController *playerController;
191 @property (nonatomic, retain) CALayer *videoSublayer;
192 @property (nonatomic, copy, nullable) NSDictionary *pixelBufferAttributes;
193 @property CGSize videoDimensions;
194 @property CGRect modelVideoLayerFrame;
195 @end
196
197 @implementation WebAVPlayerLayer {
198     RefPtr<VideoFullscreenInterfaceAVKit> _fullscreenInterface;
199     RetainPtr<WebAVPlayerController> _avPlayerController;
200     RetainPtr<CALayer> _videoSublayer;
201     RetainPtr<NSString> _videoGravity;
202 }
203
204 - (instancetype)init
205 {
206     self = [super init];
207     if (self) {
208         [self setMasksToBounds:YES];
209         _videoGravity = getAVLayerVideoGravityResizeAspect();
210     }
211     return self;
212 }
213
214 - (void)dealloc
215 {
216     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
217     [_pixelBufferAttributes release];
218     [super dealloc];
219 }
220
221 - (VideoFullscreenInterfaceAVKit*)fullscreenInterface
222 {
223     return _fullscreenInterface.get();
224 }
225
226 - (void)setFullscreenInterface:(VideoFullscreenInterfaceAVKit*)fullscreenInterface
227 {
228     _fullscreenInterface = fullscreenInterface;
229 }
230
231 - (AVPlayerController *)playerController
232 {
233     return (AVPlayerController *)_avPlayerController.get();
234 }
235
236 - (void)setPlayerController:(AVPlayerController *)playerController
237 {
238     ASSERT(!playerController || [playerController isKindOfClass:[WebAVPlayerController class]]);
239     _avPlayerController = (WebAVPlayerController *)playerController;
240 }
241
242 - (void)setVideoSublayer:(CALayer *)videoSublayer
243 {
244     _videoSublayer = videoSublayer;
245 }
246
247 - (CALayer*)videoSublayer
248 {
249     return _videoSublayer.get();
250 }
251
252 - (void)layoutSublayers
253 {
254     if ([_videoSublayer superlayer] != self)
255         return;
256
257     if (![_avPlayerController delegate])
258         return;
259
260     [_videoSublayer setPosition:CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds))];
261
262     if (self.videoDimensions.height <= 0 || self.videoDimensions.width <= 0)
263         return;
264
265     FloatRect sourceVideoFrame;
266     FloatRect targetVideoFrame;
267     float videoAspectRatio = self.videoDimensions.width / self.videoDimensions.height;
268     
269     if ([getAVLayerVideoGravityResize() isEqualToString:self.videoGravity]) {
270         sourceVideoFrame = self.modelVideoLayerFrame;
271         targetVideoFrame = self.bounds;
272     } else if ([getAVLayerVideoGravityResizeAspect() isEqualToString:self.videoGravity]) {
273         sourceVideoFrame = largestRectWithAspectRatioInsideRect(videoAspectRatio, self.modelVideoLayerFrame);
274         targetVideoFrame = largestRectWithAspectRatioInsideRect(videoAspectRatio, self.bounds);
275     } else if ([getAVLayerVideoGravityResizeAspectFill() isEqualToString:self.videoGravity]) {
276         sourceVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.modelVideoLayerFrame);
277         self.modelVideoLayerFrame = CGRectMake(0, 0, sourceVideoFrame.width(), sourceVideoFrame.height());
278         ASSERT(_fullscreenInterface->model());
279         _fullscreenInterface->model()->setVideoLayerFrame(self.modelVideoLayerFrame);
280         targetVideoFrame = smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.bounds);
281     } else
282         ASSERT_NOT_REACHED();
283
284     UIView *view = (UIView *)[_videoSublayer delegate];
285     CGAffineTransform transform = CGAffineTransformMakeScale(targetVideoFrame.width() / sourceVideoFrame.width(), targetVideoFrame.height() / sourceVideoFrame.height());
286     [view setTransform:transform];
287     
288     NSTimeInterval animationDuration = [CATransaction animationDuration];
289     dispatch_async(dispatch_get_main_queue(), ^{
290         [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
291
292         [self performSelector:@selector(resolveBounds) withObject:nil afterDelay:animationDuration + 0.1];
293     });
294 }
295
296 - (void)resolveBounds
297 {
298     [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(resolveBounds) object:nil];
299     if (![_avPlayerController delegate])
300         return;
301     
302     if ([_videoSublayer superlayer] != self)
303         return;
304     
305     if (CGRectEqualToRect(self.modelVideoLayerFrame, [self bounds]) && CGAffineTransformIsIdentity([(UIView *)[_videoSublayer delegate] transform]))
306         return;
307     
308     [CATransaction begin];
309     [CATransaction setAnimationDuration:0];
310     [CATransaction setDisableActions:YES];
311     
312     if (!CGRectEqualToRect(self.modelVideoLayerFrame, [self bounds])) {
313         self.modelVideoLayerFrame = [self bounds];
314         ASSERT(_fullscreenInterface->model());
315         _fullscreenInterface->model()->setVideoLayerFrame(self.modelVideoLayerFrame);
316     }
317     [(UIView *)[_videoSublayer delegate] setTransform:CGAffineTransformIdentity];
318     
319     [CATransaction commit];
320 }
321
322 - (void)setVideoGravity:(NSString *)videoGravity
323 {
324     _videoGravity = videoGravity;
325     
326     if (![_avPlayerController delegate])
327         return;
328
329     WebCore::VideoFullscreenModel::VideoGravity gravity = WebCore::VideoFullscreenModel::VideoGravityResizeAspect;
330     if (videoGravity == getAVLayerVideoGravityResize())
331         gravity = WebCore::VideoFullscreenModel::VideoGravityResize;
332     if (videoGravity == getAVLayerVideoGravityResizeAspect())
333         gravity = WebCore::VideoFullscreenModel::VideoGravityResizeAspect;
334     else if (videoGravity == getAVLayerVideoGravityResizeAspectFill())
335         gravity = WebCore::VideoFullscreenModel::VideoGravityResizeAspectFill;
336     else
337         ASSERT_NOT_REACHED();
338     
339     ASSERT(_fullscreenInterface->model());
340     _fullscreenInterface->model()->setVideoLayerGravity(gravity);
341 }
342
343 - (NSString *)videoGravity
344 {
345     return _videoGravity.get();
346 }
347
348 - (CGRect)videoRect
349 {
350     if (self.videoDimensions.width <= 0 || self.videoDimensions.height <= 0)
351         return self.bounds;
352     
353     float videoAspectRatio = self.videoDimensions.width / self.videoDimensions.height;
354
355     if ([getAVLayerVideoGravityResizeAspect() isEqualToString:self.videoGravity])
356         return largestRectWithAspectRatioInsideRect(videoAspectRatio, self.bounds);
357     if ([getAVLayerVideoGravityResizeAspectFill() isEqualToString:self.videoGravity])
358         return smallestRectWithAspectRatioAroundRect(videoAspectRatio, self.bounds);
359
360     return self.bounds;
361 }
362
363 + (NSSet *)keyPathsForValuesAffectingVideoRect
364 {
365     return [NSSet setWithObjects:@"videoDimensions", @"videoGravity", nil];
366 }
367
368 @end
369
370 @interface WebAVPictureInPicturePlayerLayerView : UIView
371 @end
372
373 static Class WebAVPictureInPicturePlayerLayerView_layerClass(id, SEL)
374 {
375     return [WebAVPlayerLayer class];
376 }
377
378 static WebAVPictureInPicturePlayerLayerView *allocWebAVPictureInPicturePlayerLayerViewInstance()
379 {
380     static Class theClass = nil;
381     static dispatch_once_t onceToken;
382     dispatch_once(&onceToken, ^{
383         theClass = objc_allocateClassPair(getUIViewClass(), "WebAVPictureInPicturePlayerLayerView", 0);
384         objc_registerClassPair(theClass);
385         Class metaClass = objc_getMetaClass("WebAVPictureInPicturePlayerLayerView");
386         class_addMethod(metaClass, @selector(layerClass), (IMP)WebAVPictureInPicturePlayerLayerView_layerClass, "@@:");
387     });
388     
389     return (WebAVPictureInPicturePlayerLayerView *)[theClass alloc];
390 }
391
392 @interface WebAVPlayerLayerView : __AVPlayerLayerView
393 @property (retain) UIView* videoView;
394 @end
395
396 static Class WebAVPlayerLayerView_layerClass(id, SEL)
397 {
398     return [WebAVPlayerLayer class];
399 }
400
401 static AVPlayerController *WebAVPlayerLayerView_playerController(id aSelf, SEL)
402 {
403     __AVPlayerLayerView *playerLayer = aSelf;
404     WebAVPlayerLayer *webAVPlayerLayer = (WebAVPlayerLayer *)[playerLayer playerLayer];
405     return [webAVPlayerLayer playerController];
406 }
407
408 static void WebAVPlayerLayerView_setPlayerController(id aSelf, SEL, AVPlayerController *playerController)
409 {
410     __AVPlayerLayerView *playerLayerView = aSelf;
411     WebAVPlayerLayer *webAVPlayerLayer = (WebAVPlayerLayer *)[playerLayerView playerLayer];
412     [webAVPlayerLayer setPlayerController: playerController];
413 }
414
415 static UIView *WebAVPlayerLayerView_videoView(id aSelf, SEL)
416 {
417     __AVPlayerLayerView *playerLayer = aSelf;
418     WebAVPlayerLayer *webAVPlayerLayer = (WebAVPlayerLayer *)[playerLayer playerLayer];
419     CALayer* videoLayer = [webAVPlayerLayer videoSublayer];
420     if (!videoLayer || !videoLayer.delegate)
421         return nil;
422     ASSERT([[videoLayer delegate] isKindOfClass:getUIViewClass()]);
423     return (UIView *)[videoLayer delegate];
424 }
425
426 static void WebAVPlayerLayerView_setVideoView(id aSelf, SEL, UIView *videoView)
427 {
428     __AVPlayerLayerView *playerLayerView = aSelf;
429     WebAVPlayerLayer *webAVPlayerLayer = (WebAVPlayerLayer *)[playerLayerView playerLayer];
430     [webAVPlayerLayer setVideoSublayer:[videoView layer]];
431 }
432
433 static void WebAVPlayerLayerView_startRoutingVideoToPictureInPicturePlayerLayerView(id aSelf, SEL)
434 {
435     WebAVPlayerLayerView *playerLayerView = aSelf;
436     WebAVPictureInPicturePlayerLayerView *pipView = (WebAVPictureInPicturePlayerLayerView *)[playerLayerView pictureInPicturePlayerLayerView];
437
438     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[playerLayerView playerLayer];
439     WebAVPlayerLayer *pipPlayerLayer = (WebAVPlayerLayer *)[pipView layer];
440     [playerLayer setVideoGravity:getAVLayerVideoGravityResizeAspect()];
441     [pipPlayerLayer setVideoSublayer:playerLayer.videoSublayer];
442     [pipPlayerLayer setVideoDimensions:playerLayer.videoDimensions];
443     [pipPlayerLayer setVideoGravity:playerLayer.videoGravity];
444     [pipPlayerLayer setModelVideoLayerFrame:playerLayer.modelVideoLayerFrame];
445     [pipPlayerLayer setPlayerController:playerLayer.playerController];
446     [pipPlayerLayer setFullscreenInterface:playerLayer.fullscreenInterface];
447     [pipView addSubview:playerLayerView.videoView];
448 }
449
450 static void WebAVPlayerLayerView_stopRoutingVideoToPictureInPicturePlayerLayerView(id aSelf, SEL)
451 {
452     WebAVPlayerLayerView *playerLayerView = aSelf;
453     if (UIView *videoView = playerLayerView.videoView)
454         [playerLayerView addSubview:videoView];
455     WebAVPictureInPicturePlayerLayerView *pipView = (WebAVPictureInPicturePlayerLayerView *)[playerLayerView pictureInPicturePlayerLayerView];
456     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[playerLayerView playerLayer];
457     WebAVPlayerLayer *pipPlayerLayer = (WebAVPlayerLayer *)[pipView layer];
458     [playerLayer setModelVideoLayerFrame:pipPlayerLayer.modelVideoLayerFrame];
459 }
460
461 static WebAVPictureInPicturePlayerLayerView *WebAVPlayerLayerView_pictureInPicturePlayerLayerView(id aSelf, SEL)
462 {
463     WebAVPlayerLayerView *playerLayerView = aSelf;
464     WebAVPictureInPicturePlayerLayerView *pipView = [playerLayerView valueForKey:@"_pictureInPicturePlayerLayerView"];
465     if (!pipView) {
466         pipView = [allocWebAVPictureInPicturePlayerLayerViewInstance() initWithFrame:CGRectZero];
467         [playerLayerView setValue:pipView forKey:@"_pictureInPicturePlayerLayerView"];
468     }
469     return pipView;
470 }
471
472 static void WebAVPlayerLayerView_dealloc(id aSelf, SEL)
473 {
474     WebAVPlayerLayerView *playerLayerView = aSelf;
475     RetainPtr<WebAVPictureInPicturePlayerLayerView> pipView = adoptNS([playerLayerView valueForKey:@"_pictureInPicturePlayerLayerView"]);
476     [playerLayerView setValue:nil forKey:@"_pictureInPicturePlayerLayerView"];
477     objc_super superClass { playerLayerView, get__AVPlayerLayerViewClass() };
478     auto super_dealloc = reinterpret_cast<void(*)(objc_super*, SEL)>(objc_msgSendSuper);
479     super_dealloc(&superClass, @selector(dealloc));
480 }
481
482 #pragma mark - Methods
483
484 static WebAVPlayerLayerView *allocWebAVPlayerLayerViewInstance()
485 {
486     static Class theClass = nil;
487     static dispatch_once_t onceToken;
488     dispatch_once(&onceToken, ^{
489         theClass = objc_allocateClassPair(get__AVPlayerLayerViewClass(), "WebAVPlayerLayerView", 0);
490         class_addMethod(theClass, @selector(dealloc), (IMP)WebAVPlayerLayerView_dealloc, "v@:");
491         class_addMethod(theClass, @selector(setPlayerController:), (IMP)WebAVPlayerLayerView_setPlayerController, "v@:@");
492         class_addMethod(theClass, @selector(playerController), (IMP)WebAVPlayerLayerView_playerController, "@@:");
493         class_addMethod(theClass, @selector(setVideoView:), (IMP)WebAVPlayerLayerView_setVideoView, "v@:@");
494         class_addMethod(theClass, @selector(videoView), (IMP)WebAVPlayerLayerView_videoView, "@@:");
495         class_addMethod(theClass, @selector(startRoutingVideoToPictureInPicturePlayerLayerView), (IMP)WebAVPlayerLayerView_startRoutingVideoToPictureInPicturePlayerLayerView, "v@:");
496         class_addMethod(theClass, @selector(stopRoutingVideoToPictureInPicturePlayerLayerView), (IMP)WebAVPlayerLayerView_stopRoutingVideoToPictureInPicturePlayerLayerView, "v@:");
497         class_addMethod(theClass, @selector(pictureInPicturePlayerLayerView), (IMP)WebAVPlayerLayerView_pictureInPicturePlayerLayerView, "@@:");
498         
499         class_addIvar(theClass, "_pictureInPicturePlayerLayerView", sizeof(WebAVPictureInPicturePlayerLayerView *), log2(sizeof(WebAVPictureInPicturePlayerLayerView *)), "@");
500         
501         objc_registerClassPair(theClass);
502         Class metaClass = objc_getMetaClass("WebAVPlayerLayerView");
503         class_addMethod(metaClass, @selector(layerClass), (IMP)WebAVPlayerLayerView_layerClass, "@@:");
504     });
505     return (WebAVPlayerLayerView *)[theClass alloc];
506 }
507
508 Ref<VideoFullscreenInterfaceAVKit> VideoFullscreenInterfaceAVKit::create(PlaybackSessionInterfaceAVKit& playbackSessionInterface)
509 {
510     Ref<VideoFullscreenInterfaceAVKit> interface = adoptRef(*new VideoFullscreenInterfaceAVKit(playbackSessionInterface));
511     [interface->m_playerViewControllerDelegate setFullscreenInterface:interface.ptr()];
512     return interface;
513 }
514
515 VideoFullscreenInterfaceAVKit::VideoFullscreenInterfaceAVKit(PlaybackSessionInterfaceAVKit& playbackSessionInterface)
516     : m_playbackSessionInterface(playbackSessionInterface)
517     , m_playerViewControllerDelegate(adoptNS([[WebAVPlayerViewControllerDelegate alloc] init]))
518     , m_watchdogTimer(RunLoop::main(), this, &VideoFullscreenInterfaceAVKit::watchdogTimerFired)
519 {
520 }
521
522 VideoFullscreenInterfaceAVKit::~VideoFullscreenInterfaceAVKit()
523 {
524     WebAVPlayerController* playerController = this->playerController();
525     if (playerController && playerController.externalPlaybackActive)
526         externalPlaybackChanged(false, PlaybackSessionModel::TargetTypeNone, "");
527     if (m_videoFullscreenModel)
528         m_videoFullscreenModel->removeClient(*this);
529 }
530
531 WebAVPlayerController *VideoFullscreenInterfaceAVKit::playerController() const
532 {
533     return m_playbackSessionInterface->playerController();
534 }
535
536 void VideoFullscreenInterfaceAVKit::setVideoFullscreenModel(VideoFullscreenModel* model)
537 {
538     if (m_videoFullscreenModel)
539         m_videoFullscreenModel->removeClient(*this);
540
541     m_videoFullscreenModel = model;
542
543     if (m_videoFullscreenModel)
544         m_videoFullscreenModel->addClient(*this);
545
546     hasVideoChanged(m_videoFullscreenModel ? m_videoFullscreenModel->hasVideo() : false);
547     videoDimensionsChanged(m_videoFullscreenModel ? m_videoFullscreenModel->videoDimensions() : FloatSize());
548 }
549
550 void VideoFullscreenInterfaceAVKit::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
551 {
552     m_fullscreenChangeObserver = observer;
553 }
554
555 void VideoFullscreenInterfaceAVKit::hasVideoChanged(bool hasVideo)
556 {
557     [playerController() setHasEnabledVideo:hasVideo];
558     [playerController() setHasVideo:hasVideo];
559 }
560
561 void VideoFullscreenInterfaceAVKit::videoDimensionsChanged(const FloatSize& videoDimensions)
562 {
563     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
564
565     [playerLayer setVideoDimensions:videoDimensions];
566     [playerController() setContentDimensions:videoDimensions];
567     [m_playerLayerView setNeedsLayout];
568
569     WebAVPictureInPicturePlayerLayerView *pipView = (WebAVPictureInPicturePlayerLayerView *)[m_playerLayerView pictureInPicturePlayerLayerView];
570     WebAVPlayerLayer *pipPlayerLayer = (WebAVPlayerLayer *)[pipView layer];
571     [pipPlayerLayer setVideoDimensions:playerLayer.videoDimensions];
572     [pipView setNeedsLayout];
573 }
574
575 void VideoFullscreenInterfaceAVKit::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
576 {
577     [m_playerLayerView setHidden:enabled];
578 }
579
580 #if !ENABLE(FULLSCREEN_API)
581
582 void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
583 {
584     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::applicationDidBecomeActive(%p)", this);
585     if (m_shouldReturnToFullscreenAfterEnteringForeground && m_videoFullscreenModel && m_videoFullscreenModel->isVisible()) {
586         [m_playerViewController stopPictureInPicture];
587         return;
588     }
589
590     // If we are both in PiP and in Fullscreen (i.e., via auto-PiP), and we did not stop fullscreen upon returning, it must be
591     // because the originating view is not visible, so hide the fullscreen window.
592     if (m_currentMode.hasFullscreen() && m_currentMode.hasPictureInPicture()) {
593         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError *) {
594             [m_window setHidden:YES];
595             [[m_playerViewController view] setHidden:YES];
596         }];
597     }
598 }
599
600 void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const IntRect& initialRect, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback, bool standby)
601 {
602     ASSERT(mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
603     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::setupFullscreen(%p)", this);
604
605     m_allowsPictureInPicturePlayback = allowsPictureInPicturePlayback;
606     m_videoView = &videoView;
607     m_parentView = parentView;
608     m_parentWindow = parentView.window;
609
610     ASSERT_UNUSED(standby, !standby);
611     bool isInPictureInPictureMode = m_currentMode.hasPictureInPicture();
612     m_currentMode = mode;
613     m_inlineRect = initialRect;
614
615     [CATransaction begin];
616     [CATransaction setDisableActions:YES];
617
618     if (![[m_parentView window] _isHostedInAnotherProcess]) {
619         if (!m_window)
620             m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
621         [m_window setBackgroundColor:clearUIColor()];
622         if (!m_viewController)
623             m_viewController = adoptNS([allocUIViewControllerInstance() init]);
624         [[m_viewController view] setFrame:[m_window bounds]];
625         [m_viewController _setIgnoreAppSupportedOrientations:YES];
626         [m_window setRootViewController:m_viewController.get()];
627         [m_window setWindowLevel:getUITextEffectsBeneathStatusBarWindowLevel() + 1];
628         [m_window makeKeyAndVisible];
629     }
630
631     if (!m_playerLayerView)
632         m_playerLayerView = adoptNS([allocWebAVPlayerLayerViewInstance() init]);
633     [m_playerLayerView setHidden:[playerController() isExternalPlaybackActive]];
634     [m_playerLayerView setBackgroundColor:clearUIColor()];
635
636     if (!isInPictureInPictureMode) {
637         [m_playerLayerView setVideoView:m_videoView.get()];
638         [m_playerLayerView addSubview:m_videoView.get()];
639     }
640
641     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
642
643     [playerLayer setModelVideoLayerFrame:CGRectMake(0, 0, m_inlineRect.width(), m_inlineRect.height())];
644     [playerLayer setVideoDimensions:[playerController() contentDimensions]];
645     playerLayer.fullscreenInterface = this;
646
647     if (!m_playerViewController)
648         m_playerViewController = adoptNS([allocAVPlayerViewControllerInstance() initWithPlayerLayerView:m_playerLayerView.get()]);
649
650     [m_playerViewController setShowsPlaybackControls:NO];
651     [m_playerViewController setPlayerController:(AVPlayerController *)playerController()];
652     [m_playerViewController setDelegate:m_playerViewControllerDelegate.get()];
653     [m_playerViewController setAllowsPictureInPicturePlayback:m_allowsPictureInPicturePlayback];
654
655     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
656
657     if (m_viewController) {
658         [m_viewController addChildViewController:m_playerViewController.get()];
659         [[m_viewController view] addSubview:[m_playerViewController view]];
660     } else
661         [m_parentView addSubview:[m_playerViewController view]];
662
663     [m_playerViewController view].frame = [m_parentView convertRect:m_inlineRect toView:[m_playerViewController view].superview];
664
665     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
666     [[m_playerViewController view] setAutoresizingMask:(UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin)];
667
668     [[m_playerViewController view] setNeedsLayout];
669     [[m_playerViewController view] layoutIfNeeded];
670
671     [CATransaction commit];
672
673     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
674         if (m_fullscreenChangeObserver)
675             m_fullscreenChangeObserver->didSetupFullscreen();
676     });
677 }
678
679 void VideoFullscreenInterfaceAVKit::enterFullscreen()
680 {
681     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreen(%p) %d", this, mode());
682
683     m_exitCompleted = false;
684     m_exitRequested = false;
685     m_enterRequested = true;
686
687     if (m_currentMode.isPictureInPicture())
688         enterPictureInPicture();
689     else if (m_currentMode.isFullscreen())
690         enterFullscreenStandard();
691     else
692         ASSERT_NOT_REACHED();
693 }
694
695 void VideoFullscreenInterfaceAVKit::enterPictureInPicture()
696 {
697     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterPictureInPicture(%p)", this);
698     
699     if ([m_playerViewController isPictureInPicturePossible])
700         [m_playerViewController startPictureInPicture];
701     else
702         failedToStartPictureInPicture();
703 }
704
705 void VideoFullscreenInterfaceAVKit::enterFullscreenStandard()
706 {
707     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard(%p)", this);
708
709     if ([m_playerViewController isPictureInPictureActive]) {
710         // NOTE: The fullscreen mode will be restored in prepareForPictureInPictureStopWithCompletionHandler().
711         m_shouldReturnToFullscreenWhenStoppingPiP = true;
712         [m_playerViewController stopPictureInPicture];
713         return;
714     }
715
716     [m_playerViewController enterFullScreenAnimated:YES completionHandler:[this, protectedThis = makeRefPtr(this)] (BOOL succeeded, NSError*) {
717         UNUSED_PARAM(succeeded);
718         LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard - lambda(%p) - succeeded(%s)", this, boolString(succeeded));
719         [m_playerViewController setShowsPlaybackControls:YES];
720
721         if (m_fullscreenChangeObserver)
722             m_fullscreenChangeObserver->didEnterFullscreen();
723     }];
724 }
725
726 void VideoFullscreenInterfaceAVKit::exitFullscreen(const IntRect& finalRect)
727 {
728     m_watchdogTimer.stop();
729
730     m_exitRequested = true;
731     if (m_exitCompleted) {
732         if (m_fullscreenChangeObserver)
733             m_fullscreenChangeObserver->didExitFullscreen();
734         return;
735     }
736     
737     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::exitFullscreen(%p)", this);
738     [m_playerViewController setShowsPlaybackControls:NO];
739     
740     [m_playerViewController view].frame = [m_parentView convertRect:finalRect toView:[m_playerViewController view].superview];
741
742     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
743     if ([playerLayer videoGravity] != getAVLayerVideoGravityResizeAspect())
744         [playerLayer setVideoGravity:getAVLayerVideoGravityResizeAspect()];
745     [[m_playerViewController view] layoutIfNeeded];
746
747     if (m_currentMode.isPictureInPicture()) {
748         m_shouldReturnToFullscreenWhenStoppingPiP = false;
749         [m_window setHidden:NO];
750         [m_playerViewController stopPictureInPicture];
751     } else if (m_currentMode.hasPictureInPicture() && m_currentMode.hasFullscreen()) {
752         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError*) {
753             clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
754             [m_window setHidden:NO];
755             [m_playerViewController stopPictureInPicture];
756         }];
757     } else if (m_currentMode.isFullscreen()) {
758         [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError*) () mutable {
759             m_exitCompleted = true;
760
761             [CATransaction begin];
762             [CATransaction setDisableActions:YES];
763             [m_playerLayerView setBackgroundColor:clearUIColor()];
764             [[m_playerViewController view] setBackgroundColor:clearUIColor()];
765             [CATransaction commit];
766
767             dispatch_async(dispatch_get_main_queue(), [protectedThis = WTFMove(protectedThis), this]() {
768                 if (m_fullscreenChangeObserver)
769                     m_fullscreenChangeObserver->didExitFullscreen();
770             });
771         }];
772     };
773 }
774
775 void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
776 {
777     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::cleanupFullscreen(%p)", this);
778
779     if (m_window) {
780         [m_window setHidden:YES];
781         [m_window setRootViewController:nil];
782     }
783     
784     [m_playerViewController setDelegate:nil];
785     [m_playerViewController setPlayerController:nil];
786     
787     if (m_currentMode.hasPictureInPicture())
788         [m_playerViewController stopPictureInPicture];
789     if (m_currentMode.hasFullscreen())
790         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[] (BOOL, NSError *) { }];
791     
792     [[m_playerViewController view] removeFromSuperview];
793     if (m_viewController)
794         [m_playerViewController removeFromParentViewController];
795     
796     [m_playerLayerView removeFromSuperview];
797     [[m_viewController view] removeFromSuperview];
798
799     m_playerLayerView = nil;
800     m_playerViewController = nil;
801     m_window = nil;
802     m_videoView = nil;
803     m_parentView = nil;
804     m_parentWindow = nil;
805     
806     if (m_fullscreenChangeObserver)
807         m_fullscreenChangeObserver->didCleanupFullscreen();
808
809     m_enterRequested = false;
810 }
811
812 void VideoFullscreenInterfaceAVKit::invalidate()
813 {
814     m_videoFullscreenModel = nil;
815     m_fullscreenChangeObserver = nil;
816     
817     cleanupFullscreen();
818 }
819
820 void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
821 {
822     if (!m_enterRequested)
823         return;
824     
825     if (m_currentMode.hasPictureInPicture())
826         return;
827     
828     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen(%p)", this);
829
830     [m_window setHidden:YES];
831     [[m_playerViewController view] setHidden:YES];
832
833     if (playbackSessionModel() && m_videoFullscreenModel && !m_exitRequested) {
834         playbackSessionModel()->pause();
835         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
836     }
837 }
838
839 void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const IntRect& inlineRect)
840 {
841     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::preparedToReturnToInline(%p) - visible(%s)", this, boolString(visible));
842     if (m_prepareToInlineCallback) {
843         [m_playerViewController view].frame = [m_parentView convertRect:inlineRect toView:[m_playerViewController view].superview];
844         WTF::Function<void(bool)> callback = WTFMove(m_prepareToInlineCallback);
845         callback(visible);
846     }
847 }
848
849 bool VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture() const
850 {
851     return [playerController() isPlaying] && m_currentMode.isFullscreen() && supportsPictureInPicture();
852 }
853
854 void VideoFullscreenInterfaceAVKit::fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback)
855 {
856     m_prepareToInlineCallback = WTFMove(callback);
857     if (m_fullscreenChangeObserver)
858         m_fullscreenChangeObserver->fullscreenMayReturnToInline();
859 }
860
861 void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
862 {
863     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStartPictureInPicture(%p)", this);
864     setMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
865 }
866
867 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
868 {
869     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStartPictureInPicture(%p)", this);
870     m_shouldReturnToFullscreenAfterEnteringForeground = [m_playerViewController pictureInPictureWasStartedWhenEnteringBackground];
871     [m_playerViewController setShowsPlaybackControls:YES];
872
873     if (m_currentMode.hasFullscreen()) {
874         if (![m_playerViewController pictureInPictureWasStartedWhenEnteringBackground]) {
875             [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL, NSError *) {
876                 [m_window setHidden:YES];
877                 [[m_playerViewController view] setHidden:YES];
878             }];
879         }
880     } else {
881         [m_window setHidden:YES];
882         [[m_playerViewController view] setHidden:YES];
883     }
884
885     if (m_fullscreenChangeObserver)
886         m_fullscreenChangeObserver->didEnterFullscreen();
887 }
888
889 void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
890 {
891     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture(%p)", this);
892     [m_playerViewController setShowsPlaybackControls:YES];
893
894     if (m_currentMode.hasFullscreen())
895         return;
896
897     m_exitCompleted = true;
898
899     if (m_fullscreenChangeObserver)
900         m_fullscreenChangeObserver->didEnterFullscreen();
901
902     if (m_videoFullscreenModel)
903         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
904 }
905
906 void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
907 {
908     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStopPictureInPicture(%p)", this);
909
910     m_shouldReturnToFullscreenWhenStoppingPiP = false;
911     m_shouldReturnToFullscreenAfterEnteringForeground = false;
912
913     if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop)
914         return;
915
916     [m_window setHidden:NO];
917     [[m_playerViewController view] setHidden:NO];
918
919     if (m_videoFullscreenModel)
920         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
921 }
922
923 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
924 {
925     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStopPictureInPicture(%p)", this);
926
927     if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop) {
928         clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
929         [m_playerViewController setShowsPlaybackControls:YES];
930
931         return;
932     }
933
934     m_exitCompleted = true;
935
936     [m_playerLayerView setBackgroundColor:clearUIColor()];
937     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
938
939     clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
940
941     if (m_fullscreenChangeObserver)
942         m_fullscreenChangeObserver->didExitFullscreen();
943 }
944
945 void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(void (^completionHandler)(BOOL restored))
946 {
947     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(%p)", this);
948     if (m_shouldReturnToFullscreenWhenStoppingPiP || m_shouldReturnToFullscreenAfterEnteringForeground) {
949
950         m_shouldReturnToFullscreenAfterEnteringForeground = false;
951         m_shouldReturnToFullscreenWhenStoppingPiP = false;
952         m_restoringFullscreenForPictureInPictureStop = true;
953
954         [m_window setHidden:NO];
955         [[m_playerViewController view] setHidden:NO];
956
957         [m_playerViewController enterFullScreenAnimated:YES completionHandler:^(BOOL success, NSError *error) {
958             UNUSED_PARAM(error);
959             m_restoringFullscreenForPictureInPictureStop = false;
960             setMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
961             completionHandler(success);
962             if (m_fullscreenChangeObserver)
963                 m_fullscreenChangeObserver->didEnterFullscreen();
964         }];
965         return;
966     }
967
968     fullscreenMayReturnToInline([protectedThis = makeRefPtr(this), strongCompletionHandler = adoptNS([completionHandler copy])](bool restored)  {
969         LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler lambda(%p) - restored(%s)", protectedThis.get(), boolString(restored));
970         ((void (^)(BOOL))strongCompletionHandler.get())(restored);
971     });
972 }
973
974 bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscreenInterfaceAVKit::ExitFullScreenReason reason)
975 {
976     if (!m_videoFullscreenModel)
977         return true;
978
979     if (reason == ExitFullScreenReason::PictureInPictureStarted) {
980         if ([m_playerViewController pictureInPictureWasStartedWhenEnteringBackground])
981             return false;
982
983         m_shouldReturnToFullscreenWhenStoppingPiP = m_currentMode.hasFullscreen();
984         clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
985         return true;
986     }
987
988     if (playbackSessionModel() && (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived))
989         playbackSessionModel()->pause();
990
991     BOOL finished = reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::PinchGestureHandled;
992     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
993
994     if (!m_watchdogTimer.isActive())
995         m_watchdogTimer.startOneShot(defaultWatchdogTimerInterval);
996
997     return false;
998 }
999
1000 #else // ENABLE(FULLSCREEN_API)
1001
1002 void VideoFullscreenInterfaceAVKit::applicationDidBecomeActive()
1003 {
1004     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::applicationDidBecomeActive(%p)", this);
1005
1006     // If we are both in PiP and in Fullscreen (i.e., via auto-PiP), and we did not stop fullscreen upon returning, it must be
1007     // because the originating view is not visible, so hide the fullscreen window.
1008     if (m_currentMode.hasFullscreen() && m_currentMode.hasPictureInPicture()) {
1009         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
1010             exitFullscreenHandler(success, error);
1011         }];
1012     }
1013 }
1014
1015 void VideoFullscreenInterfaceAVKit::setupFullscreen(UIView& videoView, const IntRect& initialRect, UIView* parentView, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback, bool standby)
1016 {
1017     ASSERT(standby || mode != HTMLMediaElementEnums::VideoFullscreenModeNone);
1018     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::setupFullscreen(%p)", this);
1019
1020     m_allowsPictureInPicturePlayback = allowsPictureInPicturePlayback;
1021     m_videoView = &videoView;
1022     m_parentView = parentView;
1023     m_parentWindow = parentView.window;
1024
1025     m_targetStandby = standby;
1026     m_targetMode = mode;
1027     setInlineRect(initialRect, true);
1028     doSetup();
1029 }
1030
1031 void VideoFullscreenInterfaceAVKit::enterFullscreen()
1032 {
1033     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreen(%p) %d", this, mode());
1034
1035     doEnterFullscreen();
1036 }
1037
1038 void VideoFullscreenInterfaceAVKit::exitFullscreen(const IntRect& finalRect)
1039 {
1040     m_watchdogTimer.stop();
1041
1042     m_targetMode = HTMLMediaElementEnums::VideoFullscreenModeNone;
1043
1044     setInlineRect(finalRect, true);
1045     doExitFullscreen();
1046 }
1047
1048 void VideoFullscreenInterfaceAVKit::cleanupFullscreen()
1049 {
1050     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::cleanupFullscreen(%p)", this);
1051
1052     m_cleanupNeedsReturnVideoContentLayer = true;
1053     if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
1054         m_fullscreenChangeObserver->returnVideoContentLayer();
1055         return;
1056     }
1057     m_cleanupNeedsReturnVideoContentLayer = false;
1058
1059     if (m_window) {
1060         [m_window setHidden:YES];
1061         [m_window setRootViewController:nil];
1062     }
1063     
1064     [m_playerViewController setDelegate:nil];
1065     [m_playerViewController setPlayerController:nil];
1066     
1067     if (m_currentMode.hasPictureInPicture())
1068         [m_playerViewController stopPictureInPicture];
1069     if (m_currentMode.hasFullscreen())
1070         [m_playerViewController exitFullScreenAnimated:NO completionHandler:[] (BOOL, NSError *) { }];
1071     
1072     [[m_playerViewController view] removeFromSuperview];
1073     if (m_viewController)
1074         [m_playerViewController removeFromParentViewController];
1075     
1076     [m_playerLayerView removeFromSuperview];
1077     [[m_viewController view] removeFromSuperview];
1078
1079     m_playerLayerView = nil;
1080     m_playerViewController = nil;
1081     m_window = nil;
1082     m_videoView = nil;
1083     m_parentView = nil;
1084     m_parentWindow = nil;
1085     
1086     if (m_fullscreenChangeObserver)
1087         m_fullscreenChangeObserver->didCleanupFullscreen();
1088 }
1089
1090 void VideoFullscreenInterfaceAVKit::invalidate()
1091 {
1092     m_videoFullscreenModel = nil;
1093     m_fullscreenChangeObserver = nil;
1094     
1095     cleanupFullscreen();
1096 }
1097
1098 void VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen()
1099 {
1100     if (m_currentMode.hasPictureInPicture())
1101         return;
1102     
1103     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::requestHideAndExitFullscreen(%p)", this);
1104
1105     [m_window setHidden:YES];
1106     [[m_playerViewController view] setHidden:YES];
1107
1108     if (playbackSessionModel() && m_videoFullscreenModel) {
1109         playbackSessionModel()->pause();
1110         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
1111     }
1112 }
1113
1114 void VideoFullscreenInterfaceAVKit::preparedToReturnToInline(bool visible, const IntRect& inlineRect)
1115 {
1116     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::preparedToReturnToInline(%p) - visible(%s)", this, boolString(visible));
1117     setInlineRect(inlineRect, visible);
1118     if (m_prepareToInlineCallback) {
1119         WTF::Function<void(bool)> callback = WTFMove(m_prepareToInlineCallback);
1120         callback(visible);
1121     }
1122 }
1123
1124 bool VideoFullscreenInterfaceAVKit::mayAutomaticallyShowVideoPictureInPicture() const
1125 {
1126     return [playerController() isPlaying] && (m_standby || m_currentMode.isFullscreen()) && supportsPictureInPicture();
1127 }
1128
1129 void VideoFullscreenInterfaceAVKit::fullscreenMayReturnToInline(WTF::Function<void(bool)>&& callback)
1130 {
1131     m_prepareToInlineCallback = WTFMove(callback);
1132     if (m_fullscreenChangeObserver)
1133         m_fullscreenChangeObserver->fullscreenMayReturnToInline();
1134 }
1135
1136 void VideoFullscreenInterfaceAVKit::willStartPictureInPicture()
1137 {
1138     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStartPictureInPicture(%p)", this);
1139     if (m_standby && !m_currentMode.hasVideo()) {
1140         [m_window setHidden:NO];
1141         [[m_playerViewController view] setHidden:NO];
1142     }
1143
1144     if (!m_hasVideoContentLayer)
1145         m_fullscreenChangeObserver->requestVideoContentLayer();
1146 }
1147
1148 void VideoFullscreenInterfaceAVKit::didStartPictureInPicture()
1149 {
1150     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStartPictureInPicture(%p)", this);
1151     setMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
1152     [m_playerViewController setShowsPlaybackControls:YES];
1153
1154     if (m_currentMode.hasFullscreen()) {
1155         if (![m_playerViewController pictureInPictureWasStartedWhenEnteringBackground]) {
1156             [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
1157                 exitFullscreenHandler(success, error);
1158             }];
1159         }
1160     } else {
1161         [m_window setHidden:YES];
1162         [[m_playerViewController view] setHidden:YES];
1163     }
1164
1165     if (m_enterFullscreenNeedsEnterPictureInPicture)
1166         doEnterFullscreen();
1167 }
1168
1169 void VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture()
1170 {
1171     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::failedToStartPictureInPicture(%p)", this);
1172     [m_playerViewController setShowsPlaybackControls:YES];
1173
1174     m_targetMode.setPictureInPicture(false);
1175     if (m_currentMode.hasFullscreen())
1176         return;
1177
1178     if (m_fullscreenChangeObserver)
1179         m_fullscreenChangeObserver->didEnterFullscreen();
1180
1181     if (m_videoFullscreenModel)
1182         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
1183 }
1184
1185 void VideoFullscreenInterfaceAVKit::willStopPictureInPicture()
1186 {
1187     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::willStopPictureInPicture(%p)", this);
1188
1189     m_shouldReturnToFullscreenWhenStoppingPiP = false;
1190
1191     if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop)
1192         return;
1193
1194     [m_window setHidden:NO];
1195     [[m_playerViewController view] setHidden:NO];
1196 }
1197
1198 void VideoFullscreenInterfaceAVKit::didStopPictureInPicture()
1199 {
1200     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didStopPictureInPicture(%p)", this);
1201     m_targetMode.setPictureInPicture(false);
1202
1203     if (m_currentMode.hasFullscreen() || m_restoringFullscreenForPictureInPictureStop) {
1204         clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
1205         [m_playerViewController setShowsPlaybackControls:YES];
1206
1207         if (m_exitFullscreenNeedsExitPictureInPicture)
1208             doExitFullscreen();
1209         return;
1210     }
1211
1212     [m_playerLayerView setBackgroundColor:clearUIColor()];
1213     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
1214
1215     if (m_videoFullscreenModel)
1216         m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
1217
1218     clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
1219
1220     if (m_enterFullscreenNeedsExitPictureInPicture)
1221         doEnterFullscreen();
1222
1223     if (m_exitFullscreenNeedsExitPictureInPicture)
1224         doExitFullscreen();
1225 }
1226
1227 void VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(void (^completionHandler)(BOOL restored))
1228 {
1229     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler(%p)", this);
1230     if (m_shouldReturnToFullscreenWhenStoppingPiP) {
1231
1232         m_shouldReturnToFullscreenWhenStoppingPiP = false;
1233         m_restoringFullscreenForPictureInPictureStop = true;
1234
1235         [m_window setHidden:NO];
1236         [[m_playerViewController view] setHidden:NO];
1237
1238         [m_playerViewController enterFullScreenAnimated:YES completionHandler:^(BOOL success, NSError *error) {
1239             enterFullscreenHandler(success, error);
1240             completionHandler(success);
1241         }];
1242         return;
1243     }
1244
1245     fullscreenMayReturnToInline([protectedThis = makeRefPtr(this), strongCompletionHandler = adoptNS([completionHandler copy])](bool restored)  {
1246         LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::prepareForPictureInPictureStopWithCompletionHandler lambda(%p) - restored(%s)", protectedThis.get(), boolString(restored));
1247         ((void (^)(BOOL))strongCompletionHandler.get())(restored);
1248     });
1249 }
1250
1251 bool VideoFullscreenInterfaceAVKit::shouldExitFullscreenWithReason(VideoFullscreenInterfaceAVKit::ExitFullScreenReason reason)
1252 {
1253     if (!m_videoFullscreenModel)
1254         return true;
1255
1256     if (reason == ExitFullScreenReason::PictureInPictureStarted) {
1257         m_shouldReturnToFullscreenWhenStoppingPiP = m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
1258         dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] () mutable {
1259             [m_playerViewController exitFullScreenAnimated:NO completionHandler:[protectedThis = WTFMove(protectedThis), this] (BOOL success, NSError *error) {
1260                 exitFullscreenHandler(success, error);
1261             }];
1262         });
1263         return false;
1264     }
1265
1266     if (playbackSessionModel() && (reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::RemoteControlStopEventReceived))
1267         playbackSessionModel()->pause();
1268
1269     BOOL finished = reason == ExitFullScreenReason::DoneButtonTapped || reason == ExitFullScreenReason::PinchGestureHandled;
1270     m_videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone, finished);
1271
1272     if (!m_watchdogTimer.isActive())
1273         m_watchdogTimer.startOneShot(defaultWatchdogTimerInterval);
1274
1275     return false;
1276 }
1277
1278 void VideoFullscreenInterfaceAVKit::setHasVideoContentLayer(bool value)
1279 {
1280     m_hasVideoContentLayer = value;
1281
1282     if (m_hasVideoContentLayer && m_finalizeSetupNeedsVideoContentLayer)
1283         finalizeSetup();
1284     if (!m_hasVideoContentLayer && m_cleanupNeedsReturnVideoContentLayer)
1285         cleanupFullscreen();
1286     if (!m_hasVideoContentLayer && m_returnToStandbyNeedsReturnVideoContentLayer)
1287         returnToStandby();
1288     if (!m_hasVideoContentLayer && m_finalizeSetupNeedsReturnVideoContentLayer)
1289         finalizeSetup();
1290     if (!m_hasVideoContentLayer && m_exitFullscreenNeedsReturnContentLayer)
1291         doExitFullscreen();
1292 }
1293
1294 void VideoFullscreenInterfaceAVKit::setInlineRect(const IntRect& inlineRect, bool visible)
1295 {
1296     m_inlineRect = inlineRect;
1297     m_inlineIsVisible = visible;
1298     m_hasUpdatedInlineRect = true;
1299
1300     if (m_playerViewController && m_parentView) {
1301         [CATransaction begin];
1302         [CATransaction setDisableActions:YES];
1303         [m_playerViewController view].frame = [m_parentView convertRect:inlineRect toView:[m_playerViewController view].superview];
1304         [CATransaction commit];
1305     }
1306
1307     if (m_setupNeedsInlineRect)
1308         doSetup();
1309
1310     if (m_exitFullscreenNeedInlineRect)
1311         doExitFullscreen();
1312 }
1313
1314 void VideoFullscreenInterfaceAVKit::doSetup()
1315 {
1316     Mode changes { m_currentMode.mode() ^ m_targetMode.mode() };
1317
1318     if (m_currentMode.hasVideo() && m_targetMode.hasVideo() && (m_standby != m_targetStandby)) {
1319         m_standby = m_targetStandby;
1320         finalizeSetup();
1321         return;
1322     }
1323
1324     if (!m_hasUpdatedInlineRect && m_fullscreenChangeObserver) {
1325         m_setupNeedsInlineRect = true;
1326         m_fullscreenChangeObserver->requestUpdateInlineRect();
1327         return;
1328     }
1329     m_setupNeedsInlineRect = false;
1330
1331     [CATransaction begin];
1332     [CATransaction setDisableActions:YES];
1333     if (![[m_parentView window] _isHostedInAnotherProcess] && !m_window) {
1334         if (!m_window)
1335             m_window = adoptNS([allocUIWindowInstance() initWithFrame:[[getUIScreenClass() mainScreen] bounds]]);
1336         [m_window setBackgroundColor:clearUIColor()];
1337         if (!m_viewController)
1338             m_viewController = adoptNS([allocUIViewControllerInstance() init]);
1339         [[m_viewController view] setFrame:[m_window bounds]];
1340         [m_viewController _setIgnoreAppSupportedOrientations:YES];
1341         [m_window setRootViewController:m_viewController.get()];
1342         [m_window setWindowLevel:getUITextEffectsBeneathStatusBarWindowLevel() + 1];
1343         [m_window makeKeyAndVisible];
1344     }
1345
1346     if (!m_playerLayerView)
1347         m_playerLayerView = adoptNS([allocWebAVPlayerLayerViewInstance() init]);
1348     [m_playerLayerView setHidden:[playerController() isExternalPlaybackActive]];
1349     [m_playerLayerView setBackgroundColor:clearUIColor()];
1350
1351     if (!m_currentMode.hasPictureInPicture()) {
1352         [m_playerLayerView setVideoView:m_videoView.get()];
1353         [m_playerLayerView addSubview:m_videoView.get()];
1354     }
1355
1356     WebAVPlayerLayer *playerLayer = (WebAVPlayerLayer *)[m_playerLayerView playerLayer];
1357
1358     [playerLayer setModelVideoLayerFrame:CGRectMake(0, 0, m_inlineRect.width(), m_inlineRect.height())];
1359     [playerLayer setVideoDimensions:[playerController() contentDimensions]];
1360     playerLayer.fullscreenInterface = this;
1361
1362     if (!m_playerViewController)
1363         m_playerViewController = adoptNS([allocAVPlayerViewControllerInstance() initWithPlayerLayerView:m_playerLayerView.get()]);
1364
1365     [m_playerViewController setShowsPlaybackControls:NO];
1366     [m_playerViewController setPlayerController:(AVPlayerController *)playerController()];
1367     [m_playerViewController setDelegate:m_playerViewControllerDelegate.get()];
1368     [m_playerViewController setAllowsPictureInPicturePlayback:m_allowsPictureInPicturePlayback];
1369
1370     [playerController() setPictureInPicturePossible:m_allowsPictureInPicturePlayback];
1371
1372     if (m_viewController) {
1373         [m_viewController addChildViewController:m_playerViewController.get()];
1374         [[m_viewController view] addSubview:[m_playerViewController view]];
1375     } else
1376         [m_parentView addSubview:[m_playerViewController view]];
1377
1378     [m_playerViewController view].frame = [m_parentView convertRect:m_inlineRect toView:[m_playerViewController view].superview];
1379
1380     [[m_playerViewController view] setBackgroundColor:clearUIColor()];
1381     [[m_playerViewController view] setAutoresizingMask:(UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleRightMargin)];
1382
1383     [[m_playerViewController view] setNeedsLayout];
1384     [[m_playerViewController view] layoutIfNeeded];
1385
1386     if (m_targetStandby && !m_currentMode.hasVideo()) {
1387         [m_window setHidden:YES];
1388         [[m_playerViewController view] setHidden:YES];
1389     }
1390
1391     [CATransaction commit];
1392
1393     finalizeSetup();
1394 }
1395
1396 void VideoFullscreenInterfaceAVKit::finalizeSetup()
1397 {
1398     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
1399         if (m_fullscreenChangeObserver) {
1400             if (!m_hasVideoContentLayer && m_targetMode.hasVideo()) {
1401                 m_finalizeSetupNeedsVideoContentLayer = true;
1402                 m_fullscreenChangeObserver->requestVideoContentLayer();
1403                 return;
1404             }
1405             m_finalizeSetupNeedsVideoContentLayer = false;
1406             if (m_hasVideoContentLayer && !m_targetMode.hasVideo()) {
1407                 m_finalizeSetupNeedsReturnVideoContentLayer = true;
1408                 m_fullscreenChangeObserver->returnVideoContentLayer();
1409                 return;
1410             }
1411             m_finalizeSetupNeedsReturnVideoContentLayer = false;
1412             m_fullscreenChangeObserver->didSetupFullscreen();
1413         }
1414     });
1415 }
1416
1417 void VideoFullscreenInterfaceAVKit::doEnterFullscreen()
1418 {
1419     m_standby = m_targetStandby;
1420
1421     if (m_targetMode.hasFullscreen() && !m_currentMode.hasFullscreen()) {
1422         m_enterFullscreenNeedsEnterFullscreen = true;
1423         [m_playerViewController enterFullScreenAnimated:YES completionHandler:[this, protectedThis = makeRefPtr(this)] (BOOL success, NSError *error) {
1424             enterFullscreenHandler(success, error);
1425         }];
1426         return;
1427     }
1428     m_enterFullscreenNeedsEnterFullscreen = false;
1429
1430     if (m_targetMode.hasPictureInPicture() && !m_currentMode.hasPictureInPicture()) {
1431         m_enterFullscreenNeedsEnterPictureInPicture = true;
1432         if ([m_playerViewController isPictureInPicturePossible])
1433             [m_playerViewController startPictureInPicture];
1434         else
1435             failedToStartPictureInPicture();
1436         return;
1437     }
1438     m_enterFullscreenNeedsEnterPictureInPicture = false;
1439
1440     if (!m_targetMode.hasFullscreen() && m_currentMode.hasFullscreen()) {
1441         m_enterFullscreenNeedsExitFullscreen = true;
1442         [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
1443             exitFullscreenHandler(success, error);
1444         }];
1445         return;
1446     }
1447     m_enterFullscreenNeedsExitFullscreen = false;
1448
1449     if (!m_targetMode.hasPictureInPicture() && m_currentMode.hasPictureInPicture()) {
1450         m_enterFullscreenNeedsExitPictureInPicture = true;
1451         [m_playerViewController stopPictureInPicture];
1452         return;
1453     }
1454     m_enterFullscreenNeedsExitPictureInPicture = false;
1455
1456     if (m_fullscreenChangeObserver)
1457         m_fullscreenChangeObserver->didEnterFullscreen();
1458 }
1459
1460 void VideoFullscreenInterfaceAVKit::doExitFullscreen()
1461 {
1462     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::doExitFullscreen(%p)", this);
1463
1464     if (m_currentMode.hasVideo() && !m_hasUpdatedInlineRect && m_fullscreenChangeObserver) {
1465         m_exitFullscreenNeedInlineRect = true;
1466         m_fullscreenChangeObserver->requestUpdateInlineRect();
1467         return;
1468     }
1469     m_exitFullscreenNeedInlineRect = false;
1470
1471     if (m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModeStandard)) {
1472         m_exitFullscreenNeedsExitFullscreen = true;
1473         [m_playerViewController exitFullScreenAnimated:YES completionHandler:[protectedThis = makeRefPtr(this), this] (BOOL success, NSError *error) {
1474             exitFullscreenHandler(success, error);
1475         }];
1476         return;
1477     }
1478     m_exitFullscreenNeedsExitFullscreen = false;
1479
1480     if (m_currentMode.hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
1481         m_exitFullscreenNeedsExitPictureInPicture = true;
1482         m_shouldReturnToFullscreenWhenStoppingPiP = false;
1483         [m_window setHidden:NO];
1484         [m_playerViewController stopPictureInPicture];
1485         return;
1486     }
1487     m_exitFullscreenNeedsExitPictureInPicture = false;
1488
1489     if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
1490         m_exitFullscreenNeedsReturnContentLayer = true;
1491         m_fullscreenChangeObserver->returnVideoContentLayer();
1492         return;
1493     }
1494     m_exitFullscreenNeedsReturnContentLayer = false;
1495
1496     m_standby = false;
1497
1498     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
1499         if (m_fullscreenChangeObserver)
1500             m_fullscreenChangeObserver->didExitFullscreen();
1501     });
1502 }
1503
1504 void VideoFullscreenInterfaceAVKit::exitFullscreenHandler(BOOL success, NSError *)
1505 {
1506     UNUSED_PARAM(success);
1507     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::didExitFullscreen(%p) - %d", this, success);
1508
1509     clearMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
1510
1511     if (hasMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)) {
1512         [m_window setHidden:YES];
1513         [[m_playerViewController view] setHidden:YES];
1514     } else {
1515         [CATransaction begin];
1516         [CATransaction setDisableActions:YES];
1517         [m_playerLayerView setBackgroundColor:clearUIColor()];
1518         [[m_playerViewController view] setBackgroundColor:clearUIColor()];
1519         [CATransaction commit];
1520     }
1521
1522     if (m_enterFullscreenNeedsExitFullscreen)
1523         doEnterFullscreen();
1524     
1525     if (m_exitFullscreenNeedsExitFullscreen)
1526         doExitFullscreen();
1527 }
1528
1529 void VideoFullscreenInterfaceAVKit::enterFullscreenHandler(BOOL success, NSError *)
1530 {
1531     UNUSED_PARAM(success);
1532     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::enterFullscreenStandard - lambda(%p) - success(%s)", this, boolString(success));
1533
1534     setMode(HTMLMediaElementEnums::VideoFullscreenModeStandard);
1535     [m_playerViewController setShowsPlaybackControls:YES];
1536
1537     m_restoringFullscreenForPictureInPictureStop = false;
1538
1539     if (m_enterFullscreenNeedsEnterFullscreen)
1540         doEnterFullscreen();
1541 }
1542
1543 void VideoFullscreenInterfaceAVKit::returnToStandby()
1544 {
1545     if (m_hasVideoContentLayer && m_fullscreenChangeObserver) {
1546         m_returnToStandbyNeedsReturnVideoContentLayer = true;
1547         m_fullscreenChangeObserver->returnVideoContentLayer();
1548         return;
1549     }
1550
1551     m_returnToStandbyNeedsReturnVideoContentLayer = false;
1552
1553     [m_window setHidden:YES];
1554     [[m_playerViewController view] setHidden:YES];
1555 }
1556
1557 #endif // ENABLE(FULLSCREEN_API)
1558
1559 NO_RETURN_DUE_TO_ASSERT void VideoFullscreenInterfaceAVKit::watchdogTimerFired()
1560 {
1561     LOG(Fullscreen, "VideoFullscreenInterfaceAVKit::watchdogTimerFired(%p) - no exit fullscreen response in %gs; forcing fullscreen hidden.", this, defaultWatchdogTimerInterval.value());
1562     ASSERT_NOT_REACHED();
1563     [m_window setHidden:YES];
1564     [[m_playerViewController view] setHidden:YES];
1565 }
1566
1567 void VideoFullscreenInterfaceAVKit::setMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
1568 {
1569     if ((m_currentMode.mode() & mode) == mode)
1570         return;
1571
1572     m_currentMode.setMode(mode);
1573     if (m_videoFullscreenModel)
1574         m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
1575 }
1576
1577 void VideoFullscreenInterfaceAVKit::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
1578 {
1579     if ((~m_currentMode.mode() & mode) == mode)
1580         return;
1581
1582     m_currentMode.clearMode(mode);
1583     if (m_videoFullscreenModel)
1584         m_videoFullscreenModel->fullscreenModeChanged(m_currentMode.mode());
1585 }
1586
1587 #endif // HAVE(AVKIT)
1588
1589 bool WebCore::supportsPictureInPicture()
1590 {
1591 #if PLATFORM(IOS) && HAVE(AVKIT)
1592     return [getAVPictureInPictureControllerClass() isPictureInPictureSupported];
1593 #else
1594     return false;
1595 #endif
1596 }
1597
1598 #endif // PLATFORM(IOS)