Define AVKit softlink macro
[WebKit-https.git] / Source / WebCore / platform / mac / VideoFullscreenInterfaceMac.mm
1 /*
2  * Copyright (C) 2016 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 #import "VideoFullscreenInterfaceMac.h"
28
29 #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE)
30
31 #import "IntRect.h"
32 #import "Logging.h"
33 #import "PlaybackSessionInterfaceMac.h"
34 #import "TimeRanges.h"
35 #import "VideoFullscreenChangeObserver.h"
36 #import "VideoFullscreenModel.h"
37 #import "WebPlaybackControlsManager.h"
38 #import <AVFoundation/AVTime.h>
39 #import <pal/avfoundation/MediaTimeAVFoundation.h>
40 #import <pal/spi/cocoa/AVKitSPI.h>
41 #import <pal/spi/mac/PIPSPI.h>
42
43 #import <pal/cf/CoreMediaSoftLink.h>
44
45 SOFTLINK_AVKIT_FRAMEWORK()
46 SOFT_LINK_CLASS_OPTIONAL(AVKit, AVValueTiming)
47
48 SOFT_LINK_PRIVATE_FRAMEWORK_OPTIONAL(PIP)
49 SOFT_LINK_CLASS_OPTIONAL(PIP, PIPViewController)
50
51 @class WebVideoViewContainer;
52
53 @protocol WebVideoViewContainerDelegate <NSObject>
54
55 - (void)boundsDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer;
56 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer;
57
58 @end
59
60 using WebCore::VideoFullscreenModel;
61 using WebCore::HTMLMediaElementEnums;
62 using WebCore::VideoFullscreenInterfaceMac;
63 using WebCore::VideoFullscreenChangeObserver;
64 using WebCore::PlaybackSessionModel;
65
66 @interface WebVideoViewContainer : NSView {
67     id <WebVideoViewContainerDelegate> _videoViewContainerDelegate;
68 }
69
70 @property (nonatomic, assign) id <WebVideoViewContainerDelegate> videoViewContainerDelegate;
71
72 @end
73
74 @implementation WebVideoViewContainer
75
76 @synthesize videoViewContainerDelegate=_videoViewContainerDelegate;
77
78 - (void)resizeWithOldSuperviewSize:(NSSize)oldBoundsSize
79 {
80     [super resizeWithOldSuperviewSize:oldBoundsSize];
81
82     [_videoViewContainerDelegate boundsDidChangeForVideoViewContainer:self];
83 }
84
85 - (void)viewDidMoveToSuperview
86 {
87     [super viewDidMoveToSuperview];
88
89     [_videoViewContainerDelegate superviewDidChangeForVideoViewContainer:self];
90 }
91
92 @end
93
94 enum class PIPState {
95     NotInPIP,
96     InPIP,
97     ExitingPIP
98 };
99
100 @interface WebVideoFullscreenInterfaceMacObjC : NSObject <PIPViewControllerDelegate, WebVideoViewContainerDelegate> {
101     WebCore::VideoFullscreenInterfaceMac* _videoFullscreenInterfaceMac;
102     NSSize _videoDimensions;
103     RetainPtr<PIPViewController> _pipViewController;
104     RetainPtr<NSViewController> _videoViewContainerController;
105     RetainPtr<WebVideoViewContainer> _videoViewContainer;
106     PIPState _pipState;
107     RetainPtr<NSWindow> _returningWindow;
108     NSRect _returningRect;
109     BOOL _playing;
110     BOOL _didRequestExitingPIP;
111     BOOL _exitingToStandardFullscreen;
112 }
113
114 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac;
115 - (void)invalidateFullscreenState;
116 - (void)invalidate;
117
118 // Tracking video playback state
119 @property (nonatomic) NSSize videoDimensions;
120 @property (nonatomic, getter=isPlaying) BOOL playing;
121 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate;
122
123 // Handling PIP transitions
124 @property (nonatomic, readonly) BOOL didRequestExitingPIP;
125 @property (nonatomic, getter=isExitingToStandardFullscreen) BOOL exitingToStandardFullscreen;
126
127 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window;
128 - (void)enterPIP;
129 - (void)exitPIP;
130 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window;
131
132 @end
133
134 @implementation WebVideoFullscreenInterfaceMacObjC
135
136 @synthesize playing=_playing;
137 @synthesize videoDimensions=_videoDimensions;
138 @synthesize didRequestExitingPIP=_didRequestExitingPIP;
139 @synthesize exitingToStandardFullscreen=_exitingToStandardFullscreen;
140
141 - (instancetype)initWithVideoFullscreenInterfaceMac:(WebCore::VideoFullscreenInterfaceMac*)videoFullscreenInterfaceMac
142 {
143     if (!(self = [super init]))
144         return nil;
145
146     _videoFullscreenInterfaceMac = videoFullscreenInterfaceMac;
147     _pipState = PIPState::NotInPIP;
148
149     return self;
150 }
151
152 - (void)invalidateFullscreenState
153 {
154     [_pipViewController setDelegate:nil];
155     _pipViewController = nil;
156     [_videoViewContainer removeFromSuperview];
157     [_videoViewContainer setVideoViewContainerDelegate:nil];
158     _videoViewContainer = nil;
159     _videoViewContainerController = nil;
160     _pipState = PIPState::NotInPIP;
161     _didRequestExitingPIP = NO;
162     _exitingToStandardFullscreen = NO;
163     _returningWindow = nil;
164     _returningRect = NSZeroRect;
165 }
166
167 - (void)invalidate
168 {
169     [self invalidateFullscreenState];
170     _videoFullscreenInterfaceMac = nullptr;
171     _videoDimensions = NSZeroSize;
172 }
173
174 - (void)updateIsPlaying:(BOOL)isPlaying newPlaybackRate:(float)playbackRate
175 {
176     _playing = isPlaying && playbackRate;
177
178     [_pipViewController setPlaying:_playing];
179 }
180
181 - (void)setVideoDimensions:(NSSize)videoDimensions
182 {
183     _videoDimensions = videoDimensions;
184
185     [_pipViewController setAspectRatio:_videoDimensions];
186 }
187
188 - (void)setUpPIPForVideoView:(NSView *)videoView withFrame:(NSRect)frame inWindow:(NSWindow *)window
189 {
190     ASSERT(!_pipViewController);
191     ASSERT(!_videoViewContainerController);
192     ASSERT(!_videoViewContainer);
193
194     _pipViewController = adoptNS([allocPIPViewControllerInstance() init]);
195     [_pipViewController setDelegate:self];
196     [_pipViewController setUserCanResize:YES];
197     [_pipViewController setPlaying:_playing];
198     [self setVideoDimensions:NSEqualSizes(_videoDimensions, NSZeroSize) ? frame.size : _videoDimensions];
199     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
200         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspectFill);
201
202     _videoViewContainer = adoptNS([[WebVideoViewContainer alloc] initWithFrame:frame]);
203     [_videoViewContainer setVideoViewContainerDelegate:self];
204     [_videoViewContainer addSubview:videoView];
205     videoView.frame = [_videoViewContainer bounds];
206     videoView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
207
208     _videoViewContainerController = adoptNS([[NSViewController alloc] init]);
209     [_videoViewContainerController setView:_videoViewContainer.get()];
210     [window.contentView addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
211 }
212
213 - (void)enterPIP
214 {
215     if (_pipState == PIPState::InPIP)
216         return;
217
218     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorBlack);
219     [_pipViewController presentViewControllerAsPictureInPicture:_videoViewContainerController.get()];
220     _pipState = PIPState::InPIP;
221 }
222
223 - (void)exitPIP
224 {
225     if (_pipState != PIPState::InPIP || !_pipViewController || !_videoViewContainerController)
226         return;
227
228     _didRequestExitingPIP = YES;
229     [_videoViewContainerController view].layer.backgroundColor = CGColorGetConstantColor(kCGColorClear);
230     [_pipViewController dismissViewController:_videoViewContainerController.get()];
231     _pipState = PIPState::ExitingPIP;
232 }
233
234 - (void)exitPIPAnimatingToRect:(NSRect)rect inWindow:(NSWindow *)window
235 {
236     _returningWindow = window;
237     _returningRect = rect;
238     
239     [_pipViewController setReplacementRect:rect];
240     [_pipViewController setReplacementWindow:window];
241
242     [self exitPIP];
243 }
244
245 // WebVideoViewContainerDelegate
246
247 - (void)boundsDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
248 {
249     if (!_videoViewContainer || !_pipViewController)
250         return;
251
252     ASSERT_UNUSED(videoViewContainer, videoViewContainer == _videoViewContainer);
253
254     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel())
255         _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
256 }
257
258 - (void)superviewDidChangeForVideoViewContainer:(WebVideoViewContainer *)videoViewContainer
259 {
260     if (!_videoViewContainer || !_pipViewController)
261         return;
262
263     ASSERT(videoViewContainer == _videoViewContainer);
264
265     if (![videoViewContainer isDescendantOf:[_pipViewController view]])
266         return;
267
268     // Once the view is moved into the pip view, make sure it resizes with the pip view.
269     videoViewContainer.frame = [videoViewContainer superview].bounds;
270     videoViewContainer.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
271 }
272
273 // PIPViewControllerDelegate
274
275 - (BOOL)pipShouldClose:(PIPViewController *)pip
276 {
277     ASSERT_UNUSED(pip, pip == _pipViewController);
278
279     if (!_videoFullscreenInterfaceMac || !_videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
280         return YES;
281
282     _didRequestExitingPIP = YES;
283     _videoFullscreenInterfaceMac->videoFullscreenChangeObserver()->fullscreenMayReturnToInline();
284
285     return NO;
286 }
287
288 - (void)pipDidClose:(PIPViewController *)pip
289 {
290     ASSERT_UNUSED(pip, pip == _pipViewController);
291
292     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->videoFullscreenModel() && _videoViewContainer && _returningWindow && !NSEqualRects(_returningRect, NSZeroRect)) {
293         [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
294             context.allowsImplicitAnimation = NO;
295             [_videoViewContainer setFrame:_returningRect];
296             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerFrame([_videoViewContainer bounds]);
297             _videoFullscreenInterfaceMac->videoFullscreenModel()->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
298
299             [[_returningWindow contentView] addSubview:_videoViewContainer.get() positioned:NSWindowAbove relativeTo:nil];
300         } completionHandler:nil];
301     }
302
303     if (_videoFullscreenInterfaceMac) {
304         if (!self.isExitingToStandardFullscreen) {
305             if (VideoFullscreenModel* videoFullscreenModel = _videoFullscreenInterfaceMac->videoFullscreenModel()) {
306                 videoFullscreenModel->requestFullscreenMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
307                 videoFullscreenModel->setVideoLayerGravity(VideoFullscreenModel::VideoGravityResizeAspect);
308             }
309         }
310
311         _videoFullscreenInterfaceMac->clearMode(HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
312
313         if (VideoFullscreenChangeObserver* fullscreenChangeObserver = _videoFullscreenInterfaceMac->videoFullscreenChangeObserver())
314             fullscreenChangeObserver->didExitFullscreen();
315     }
316 }
317
318 - (void)pipActionPlay:(PIPViewController *)pip
319 {
320     ASSERT_UNUSED(pip, pip == _pipViewController);
321
322     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
323         _videoFullscreenInterfaceMac->playbackSessionModel()->play();
324 }
325
326 - (void)pipActionPause:(PIPViewController *)pip
327 {
328     ASSERT_UNUSED(pip, pip == _pipViewController);
329
330     if (_videoFullscreenInterfaceMac && _videoFullscreenInterfaceMac->playbackSessionModel())
331         _videoFullscreenInterfaceMac->playbackSessionModel()->pause();
332 }
333
334 - (void)pipActionStop:(PIPViewController *)pip
335 {
336     ASSERT_UNUSED(pip, pip == _pipViewController);
337
338     if (!_videoFullscreenInterfaceMac)
339         return;
340
341     if (PlaybackSessionModel* playbackSessionModel = _videoFullscreenInterfaceMac->playbackSessionModel())
342         playbackSessionModel->pause();
343
344     // FIXME 25096170: Should animate only if the page with the video is unobscured. For now, always close without animation.
345     [self exitPIP];
346 }
347
348 @end
349
350 namespace WebCore {
351 using namespace PAL;
352
353 VideoFullscreenInterfaceMac::VideoFullscreenInterfaceMac(PlaybackSessionInterfaceMac& playbackSessionInterface)
354     : m_playbackSessionInterface(playbackSessionInterface)
355 {
356     ASSERT(m_playbackSessionInterface->playbackSessionModel());
357     auto model = m_playbackSessionInterface->playbackSessionModel();
358     model->addClient(*this);
359     [videoFullscreenInterfaceObjC() updateIsPlaying:model->isPlaying() newPlaybackRate:model->playbackRate()];
360 }
361
362 VideoFullscreenInterfaceMac::~VideoFullscreenInterfaceMac()
363 {
364     if (m_playbackSessionInterface->playbackSessionModel())
365         m_playbackSessionInterface->playbackSessionModel()->removeClient(*this);
366     if (m_videoFullscreenModel)
367         m_videoFullscreenModel->removeClient(*this);
368 }
369
370 void VideoFullscreenInterfaceMac::setVideoFullscreenModel(VideoFullscreenModel* model)
371 {
372     if (m_videoFullscreenModel)
373         m_videoFullscreenModel->removeClient(*this);
374     m_videoFullscreenModel = model;
375     if (m_videoFullscreenModel)
376         m_videoFullscreenModel->addClient(*this);
377 }
378
379 void VideoFullscreenInterfaceMac::setVideoFullscreenChangeObserver(VideoFullscreenChangeObserver* observer)
380 {
381     m_fullscreenChangeObserver = observer;
382 }
383
384 void VideoFullscreenInterfaceMac::setMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
385 {
386     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode | mode;
387     if (m_mode == newMode)
388         return;
389
390     m_mode = newMode;
391     if (m_videoFullscreenModel)
392         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
393 }
394
395 void VideoFullscreenInterfaceMac::clearMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
396 {
397     HTMLMediaElementEnums::VideoFullscreenMode newMode = m_mode & ~mode;
398     if (m_mode == newMode)
399         return;
400
401     m_mode = newMode;
402     if (m_videoFullscreenModel)
403         m_videoFullscreenModel->fullscreenModeChanged(m_mode);
404 }
405
406 void VideoFullscreenInterfaceMac::rateChanged(bool isPlaying, float playbackRate)
407 {
408     [videoFullscreenInterfaceObjC() updateIsPlaying:isPlaying newPlaybackRate:playbackRate];
409 }
410
411 void VideoFullscreenInterfaceMac::ensureControlsManager()
412 {
413     m_playbackSessionInterface->ensureControlsManager();
414 }
415
416 WebVideoFullscreenInterfaceMacObjC *VideoFullscreenInterfaceMac::videoFullscreenInterfaceObjC()
417 {
418     if (!m_webVideoFullscreenInterfaceObjC)
419         m_webVideoFullscreenInterfaceObjC = adoptNS([[WebVideoFullscreenInterfaceMacObjC alloc] initWithVideoFullscreenInterfaceMac:this]);
420
421     return m_webVideoFullscreenInterfaceObjC.get();
422 }
423
424 void VideoFullscreenInterfaceMac::setupFullscreen(NSView& layerHostedView, const IntRect& initialRect, NSWindow *parentWindow, HTMLMediaElementEnums::VideoFullscreenMode mode, bool allowsPictureInPicturePlayback)
425 {
426     LOG(Fullscreen, "VideoFullscreenInterfaceMac::setupFullscreen(%p), initialRect:{%d, %d, %d, %d}, parentWindow:%p, mode:%d", this, initialRect.x(), initialRect.y(), initialRect.width(), initialRect.height(), parentWindow, mode);
427
428     UNUSED_PARAM(allowsPictureInPicturePlayback);
429     ASSERT(mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture);
430
431     m_mode = mode;
432
433     [videoFullscreenInterfaceObjC() setUpPIPForVideoView:&layerHostedView withFrame:(NSRect)initialRect inWindow:parentWindow];
434
435     dispatch_async(dispatch_get_main_queue(), [protectedThis = makeRefPtr(this), this] {
436         if (m_fullscreenChangeObserver)
437             m_fullscreenChangeObserver->didSetupFullscreen();
438     });
439 }
440
441 void VideoFullscreenInterfaceMac::enterFullscreen()
442 {
443     LOG(Fullscreen, "VideoFullscreenInterfaceMac::enterFullscreen(%p)", this);
444
445     if (mode() == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) {
446         [m_webVideoFullscreenInterfaceObjC enterPIP];
447
448 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
449         [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:YES];
450 #endif
451
452         if (m_fullscreenChangeObserver)
453             m_fullscreenChangeObserver->didEnterFullscreen();
454     }
455 }
456
457 void VideoFullscreenInterfaceMac::exitFullscreen(const IntRect& finalRect, NSWindow *parentWindow)
458 {
459     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreen(%p), finalRect:{%d, %d, %d, %d}, parentWindow:%p", this, finalRect.x(), finalRect.y(), finalRect.width(), finalRect.height(), parentWindow);
460
461 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
462     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
463 #endif
464
465     if ([m_webVideoFullscreenInterfaceObjC didRequestExitingPIP])
466         return;
467
468     if (finalRect.isEmpty())
469         [m_webVideoFullscreenInterfaceObjC exitPIP];
470     else
471         [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:finalRect inWindow:parentWindow];
472 }
473
474 void VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenMode mode)
475 {
476     LOG(Fullscreen, "VideoFullscreenInterfaceMac::exitFullscreenWithoutAnimationToMode(%p), mode:%d", this, mode);
477
478 #if ENABLE(WEB_PLAYBACK_CONTROLS_MANAGER)
479     [m_playbackSessionInterface->playBackControlsManager() setPictureInPictureActive:NO];
480 #endif
481
482     if ([m_webVideoFullscreenInterfaceObjC didRequestExitingPIP])
483         return;
484
485     bool isExitingToStandardFullscreen = mode == HTMLMediaElementEnums::VideoFullscreenModeStandard;
486     // On Mac, standard fullscreen is handled by the Fullscreen API and not by VideoFullscreenManager.
487     // Just update m_mode directly to HTMLMediaElementEnums::VideoFullscreenModeStandard in that case to keep
488     // m_mode in sync with the fullscreen mode in HTMLMediaElement.
489     if (isExitingToStandardFullscreen)
490         m_mode = HTMLMediaElementEnums::VideoFullscreenModeStandard;
491
492     [m_webVideoFullscreenInterfaceObjC setExitingToStandardFullscreen:isExitingToStandardFullscreen];
493     [m_webVideoFullscreenInterfaceObjC exitPIP];
494 }
495
496 void VideoFullscreenInterfaceMac::cleanupFullscreen()
497 {
498     LOG(Fullscreen, "VideoFullscreenInterfaceMac::cleanupFullscreen(%p)", this);
499
500     [m_webVideoFullscreenInterfaceObjC exitPIP];
501     [m_webVideoFullscreenInterfaceObjC invalidateFullscreenState];
502
503     if (m_fullscreenChangeObserver)
504         m_fullscreenChangeObserver->didCleanupFullscreen();
505 }
506
507 void VideoFullscreenInterfaceMac::invalidate()
508 {
509     LOG(Fullscreen, "VideoFullscreenInterfaceMac::invalidate(%p)", this);
510
511     m_videoFullscreenModel = nil;
512     m_fullscreenChangeObserver = nil;
513
514     cleanupFullscreen();
515
516     [m_webVideoFullscreenInterfaceObjC invalidate];
517     m_webVideoFullscreenInterfaceObjC = nil;
518 }
519
520 #if !LOG_DISABLED
521 static const char* boolString(bool val)
522 {
523     return val ? "true" : "false";
524 }
525 #endif
526
527 void VideoFullscreenInterfaceMac::preparedToReturnToInline(bool visible, const IntRect& inlineRect, NSWindow *parentWindow)
528 {
529     LOG(Fullscreen, "VideoFullscreenInterfaceMac::preparedToReturnToInline(%p), visible:%s, inlineRect:{%d, %d, %d, %d}, parentWindow:%p", this, boolString(visible), inlineRect.x(), inlineRect.y(), inlineRect.width(), inlineRect.height(), parentWindow);
530
531     if (!visible) {
532         [m_webVideoFullscreenInterfaceObjC exitPIP];
533         return;
534     }
535
536     ASSERT(parentWindow);
537     [m_webVideoFullscreenInterfaceObjC exitPIPAnimatingToRect:(NSRect)inlineRect inWindow:parentWindow];
538 }
539
540 void VideoFullscreenInterfaceMac::externalPlaybackChanged(bool enabled, PlaybackSessionModel::ExternalPlaybackTargetType, const String&)
541 {
542     LOG(Fullscreen, "VideoFullscreenInterfaceMac::externalPlaybackChanged(%p), enabled:%s", this, boolString(enabled));
543
544     if (enabled && m_mode == HTMLMediaElementEnums::VideoFullscreenModePictureInPicture)
545         exitFullscreen(IntRect(), nil);
546 }
547
548 void VideoFullscreenInterfaceMac::hasVideoChanged(bool hasVideo)
549 {
550     LOG(Fullscreen, "VideoFullscreenInterfaceMac::hasVideoChanged(%p):%s", this, boolString(hasVideo));
551
552     if (!hasVideo)
553         exitFullscreenWithoutAnimationToMode(HTMLMediaElementEnums::VideoFullscreenModeNone);
554 }
555
556 void VideoFullscreenInterfaceMac::videoDimensionsChanged(const FloatSize& videoDimensions)
557 {
558     LOG(Fullscreen, "VideoFullscreenInterfaceMac::videoDimensionsChanged(%p), width:%.0f, height:%.0f", this, videoDimensions.width(), videoDimensions.height());
559
560     // Width and height can be zero when we are transitioning from one video to another. Ignore zero values.
561     if (!videoDimensions.isZero())
562         [m_webVideoFullscreenInterfaceObjC setVideoDimensions:videoDimensions];
563 }
564
565 bool VideoFullscreenInterfaceMac::isPlayingVideoInEnhancedFullscreen() const
566 {
567     return hasMode(WebCore::HTMLMediaElementEnums::VideoFullscreenModePictureInPicture) && [m_webVideoFullscreenInterfaceObjC isPlaying];
568 }
569
570 bool supportsPictureInPicture()
571 {
572     return PIPLibrary() && getPIPViewControllerClass();
573 }
574
575 }
576
577 #endif